Skip to main content Skip to footer

Spread Windows Forms and Undo Redo

Spread Windows Forms allows you to undo or redo various actions performed by the end user. This can be useful for restoring deleted text and other actions. You can use the UndoAction class and several specific classes that correspond to user actions. There is also a manager class that keeps track of the end-user actions that can be undone and re-done. The SpreadView class and FpSpread class have properties, AllowUndo and UndoManager, which turn on and off the undo or redo feature and return the UndoManager for that SpreadView instance, respectively. Each SpreadView has its own UndoManager. The UndoAction class is an abstract class that inherits from Action and adds new methods to the class: Undo and SaveUndoState. It also inherits the PerformAction method from Action. SaveUndoState is used to save undo state information (in fields of the class). PerformAction is used to perform the action. Undo is used to reverse the action (using the undo state information in the fields). Each of the classes inheriting from UndoAction is designed to do one specific action (for example, edit a cell, resize a column, move a range, and so on), and to undo that action. All relevant information to do that action should be passed into the constructor for the object, and all relevant information to undo that action should be stored in the SaveUndoState implementation. Once the UndoAction object is created, the variables of that specific action are fixed (specified by the values passed to the constructor). For example, edit cell A1 in sheet1 and change the value to "test", resize column B to 24 pixels, and move the range C4:F6 to A1:D3. The action can only do that specific action in that specific way. The UndoManager class manages the undo and redo stacks. It keeps track of which actions have been done and undone, and in what order. An UndoAction must be passed into the PerformUndoAction method of UndoManager to do the action in order for it to be undoable by the UndoManager. When that happens, the UndoManager pushes the UndoAction onto the undo stack and calls PerformAction on the UndoAction, and then the CanUndo method returns True (indicating there is something to undo). When CanUndo returns False, that means the undo stack is empty, and there is no action ready to undo. You might want to use this to disable the Undo menu item in the Edit menu, for example, if your application has an Edit menu. When an action is ready to undo, you can call Undo on the UndoManager, and it moves the last action performed from the undo stack to the redo stack, and calls Undo on the action, and then the CanRedo method returns True (indicating there is something to redo). You can call PerformAction on the UndoManager with a sequence of UndoAction objects, and it performs each action in sequence, and remembers each action and the order in which they are done. Then you can call Undo to undo some of those actions, and each can be re-done with Redo (and then un-done again with Undo). But, when you call PerformAction to perform a new action, if there are any actions pending in the redo stack, those actions are cleared, and CanRedo returns False (that is, once you perform a new action, you will not be able to redo any actions that you have undone with Undo). That is why the PushUndo method in the UndoManager class has a flag to indicate whether the redo stack should be cleared when the action is pushed onto the undo stack. Some of the UndoAction classes will be replacing Action objects in the action maps, so that those actions are routed through the UndoManager and become undoable. Other UndoAction classes will not be part of the action maps, but instead are used in the SheetView or SpreadView code to make the action undoable. The input maps include items to map the Ctrl+Z and Ctrl+Y keys to the UndoAction and RedoAction action objects, respectively. These actions make calls into the UndoManager to the Undo and Redo methods. You can use the following code to manage Undo. The first three buttons can be used to copy, cut, or paste data. The fourth button uses the Undo method. The PerformUndoAction method causes the action to occur and adds it to the list of actions that can be undone. C#

private void button1_Click(object sender, EventArgs e)  
        {           
            fpSpread1.Sheets[0].ClipboardCopy();             
        }  

        private void button2_Click(object sender, EventArgs e)  
        {  
            FarPoint.Win.Spread.UndoRedo.ClipboardCutUndoAction cutAction = new FarPoint.Win.Spread.UndoRedo.ClipboardCutUndoAction();  
            fpSpread1.UndoManager.PerformUndoAction(cutAction);  
        }  

        private void button3_Click(object sender, EventArgs e)  
        {  
            FarPoint.Win.Spread.UndoRedo.ClipboardPasteUndoAction pasteAction = new FarPoint.Win.Spread.UndoRedo.ClipboardPasteUndoAction();  
            fpSpread1.UndoManager.PerformUndoAction(pasteAction);  
        }  

        private void button4_Click(object sender, EventArgs e)  
        {  
            fpSpread1.UndoManager.Undo();  
        }  

VB

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click  
        FpSpread1.Sheets(0).ClipboardCopy()  
    End Sub  

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click  
        Dim cutAction As New FarPoint.Win.Spread.UndoRedo.ClipboardCutUndoAction()  
        FpSpread1.UndoManager.PerformUndoAction(cutAction)  
    End Sub  

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click  
        Dim pasteAction As New FarPoint.Win.Spread.UndoRedo.ClipboardPasteUndoAction()  
        FpSpread1.UndoManager.PerformUndoAction(pasteAction)  
    End Sub  

    Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click  
        FpSpread1.UndoManager.Undo()  
    End Sub  

This example gets the CanUndo value, the number of items in the undo list, and the undo actions and displays the result in a list box. C#

if (fpSpread1.UndoManager.CanUndo == true)  
            {  
            listBox1.Items.Add(fpSpread1.UndoManager.CanUndo);  
            for (int i = 0; i<=fpSpread1.UndoManager.UndoList.Count-1; i++)  
            {  
                listBox1.Items.Add(fpSpread1.UndoManager.UndoList.Count);  
                listBox1.Items.Add(fpSpread1.UndoManager.UndoList[i]);  
            }

VB

If FpSpread1.UndoManager.CanUndo() = True Then  
            ListBox1.Items.Add(FpSpread1.UndoManager.CanUndo())  
            For i = 0 To FpSpread1.UndoManager.UndoList.Count - 1  
                ListBox1.Items.Add(FpSpread1.UndoManager.UndoList.Count)  
                ListBox1.Items.Add(FpSpread1.UndoManager.UndoList.Item(i))  
            Next  
        End If  

You can undo actions done through code, but you have to set up the UndoAction yourself. Here is code to show you how to set this up. Press the button to undo the sort after sorting the column. undosort Image created from sample code C#

public class SortRowsAction : FarPoint.Win.Spread.UndoRedo.UndoAction  
  {  

    FarPoint.Win.Spread.SheetView sheetView;  
    FarPoint.Win.Spread.SortInfo[] sortinfo;  
    System.Collections.ArrayList al;  

    public SortRowsAction()  
    {  

    }  

    public SortRowsAction(FarPoint.Win.Spread.SheetView sheetView, FarPoint.Win.Spread.SortInfo[] si)  
    {  
      this.sheetView = sheetView;  
      this.sortinfo = si;  
    }  

    public override bool PerformUndoAction(object sender)  
    {  
      FarPoint.Win.Spread.SpreadView spreadView = null;  
      if (sender is FarPoint.Win.Spread.SpreadView)  
      {  
        spreadView = (FarPoint.Win.Spread.SpreadView)sender;  
      }  
      else  
      {  
        return false;  
      }  

      if (sheetView == null)  
      {  
        sheetView = spreadView.GetSheetView();  
      }  
      if ((SaveUndoState()) & (sheetView != null))  
      {  
        sheetView.SortRows(0, sheetView.RowCount, this.sortinfo);  
        return true;  
      }  
      return false;  
    }  

    protected override bool SaveUndoState()  
    {  
      if ((sheetView != null))  
      {  
        if (al == null)  
        {  
          al = new System.Collections.ArrayList();  
            for (int i = 0; i<=sheetView.RowCount-1; i++)            
          {  
            al.Add(sheetView.GetViewRowFromModelRow(i));  
          }  
        }  
      }  
      return (al != null);  
    }  

    public override bool Undo(object sender)  
    {  
      FarPoint.Win.Spread.SpreadView spreadView = null;  
      if (sender is FarPoint.Win.Spread.SpreadView)  
      {  
        spreadView = (FarPoint.Win.Spread.SpreadView)sender;  
      }  
      else  
      {  
        return false;  
      }  

      if ((al != null))  
      {  
          for (int i = 0; i<=sheetView.RowCount-1; i++)          
        {  
          sheetView.Models.SetViewRowIndex(i,(int)al[i]);  
        }  
        return true;  
      }  
      return false;  
    }  
  }  

        private void Undo_Load(object sender, EventArgs e)  
        {  
            fpSpread1.Sheets[0].Columns[0].AllowAutoSort = true;  
            fpSpread1.Sheets[0].Cells[0, 0].Text = "Z";  
            fpSpread1.Sheets[0].Cells[1, 0].Text = "A";  
            fpSpread1.Sheets[0].Cells[2, 0].Text = "C";  
        }  

        private void button1_Click(object sender, EventArgs e)  
        {  
            FarPoint.Win.Spread.SortInfo[] si = new FarPoint.Win.Spread.SortInfo[] { new FarPoint.Win.Spread.SortInfo(0, true) };  
            SortRowsAction sra = new SortRowsAction(fpSpread1.Sheets[0], si);  
            fpSpread1.UndoManager.PerformUndoAction(sra);  
        }  

VB

Public Class SortRowsAction  
        Inherits FarPoint.Win.Spread.UndoRedo.UndoAction  

        Dim sheetView As FarPoint.Win.Spread.SheetView  
        Dim sortinfo() As FarPoint.Win.Spread.SortInfo  
        Dim al As ArrayList  

        Public Sub New()  

        End Sub  

        Public Sub New(ByVal sheetView As FarPoint.Win.Spread.SheetView, ByVal si() As FarPoint.Win.Spread.SortInfo)  
            Me.sheetView = sheetView  
            Me.sortinfo = si  
        End Sub  

        Public Overrides Function PerformUndoAction(ByVal sender As Object) As Boolean  
            Dim spreadView As FarPoint.Win.Spread.SpreadView = Nothing  
            If TypeOf sender Is FarPoint.Win.Spread.SpreadView Then  
                spreadView = CType(sender, FarPoint.Win.Spread.SpreadView)  
            Else  
                Return False  
            End If  

            If sheetView Is Nothing Then  
                sheetView = spreadView.GetSheetView  
            End If  
            If (SaveUndoState()) And Not (sheetView Is Nothing) Then  
                sheetView.SortRows(0, sheetView.RowCount, Me.sortinfo)  
                Return True  
            End If  
            Return False  
        End Function  

        Protected Overrides Function SaveUndoState() As Boolean  
            If Not (sheetView Is Nothing) Then  
                If al Is Nothing Then  
                    al = New ArrayList  
                    For i As Integer = 0 To sheetView.RowCount - 1  
                        al.Add(sheetView.GetViewRowFromModelRow(i))  
                    Next  
                End If  
            End If  
            Return Not (al Is Nothing)  
        End Function  

        Public Overrides Function Undo(ByVal sender As Object) As Boolean  
            Dim spreadView As FarPoint.Win.Spread.SpreadView = Nothing  
            If TypeOf sender Is FarPoint.Win.Spread.SpreadView Then  
                spreadView = CType(sender, FarPoint.Win.Spread.SpreadView)  
            Else  
                Return False  
            End If  

            If Not (al Is Nothing) Then  
                For i As Integer = 0 To sheetView.RowCount - 1  
                    sheetView.Models.SetViewRowIndex(i, al(i))  
                Next  
                Return True  
            End If  
            Return False  
        End Function  
    End Class  

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click  
        Dim si() As FarPoint.Win.Spread.SortInfo = New FarPoint.Win.Spread.SortInfo() {New FarPoint.Win.Spread.SortInfo(0, True)}  
        Dim sra As New SortRowsAction(FpSpread1.Sheets(0), si)  
        FpSpread1.UndoManager.PerformUndoAction(sra)  
    End Sub  

    Private Sub Undo_Load(sender As Object, e As EventArgs) Handles MyBase.Load  
        FpSpread1.Sheets(0).Columns(0).AllowAutoSort = True  
        FpSpread1.Sheets(0).Cells(0, 0).Text = "Z"  
        FpSpread1.Sheets(0).Cells(1, 0).Text = "A"  
        FpSpread1.Sheets(0).Cells(2, 0).Text = "C"  
    End Sub  

MESCIUS inc.

comments powered by Disqus