Undo Redo in Windows Forms Grid Control

8 Aug 20238 minutes to read

GridControl gives support for Undo/Redo functionality. GridControl keeps a track on all the operations undergone, in a particular class GridModelCommandManager. The Undo/Redo operations can be done by using commands, methods and keyboard shortcuts.

Basic Commands

GridControl has GridModelCommandManager class that implements support for the Undo/Redo commands in a grid. If an operation in a GridControl is done then the changes made will get tracked and stored in stack structures which will be stored in this class.

GridControl has a property CommandStack which will return a reference to GridModelCommandManager. Undo/Redo operations can be enabled/disabled through this property.

// Turns on Undo/Redo buffer

this.gridControl1.CommandStack.Enabled = true;

// Turns off Undo/Redo buffer
this.gridControl1.CommandStack.Enabled = false;
' Turns on Undo/Redo buffer

Me.gridControl1.CommandStack.Enabled = True

' Turns off Undo/Redo buffer
Me.gridControl1.CommandStack.Enabled = False

Undo

The undo operation can be done in GridControl by using the CommandStack.Undo method. By default, GridControl also give support for undoing the actions using keyboard shortcuts. Use Ctrl+Z combination for Undo operation to happen.

// Makes the undo operation
this.gridControl1.CommandStack.Undo();

// Clears the Undo buffer
this.gridControl1.CommandStack.Undo.Clear();
' Makes the undo operation
Me.gridControl1.CommandStack.Undo()

' Clears the Undo buffer
Me.gridControl1.CommandStack.Undo.Clear()

Redo

The redo operation can be done by using the CommandStack.Redo method. Ctrl+Y combination is the keyboard shortcut for the redoing process.

// Makes the redo operation
this.gridControl1.CommandStack.Redo();

// Clears the Undo buffer
this.gridControl1.CommandStack.Redo.Clear();
' Makes the redo operation
Me.gridControl1.CommandStack.Redo()

' Clears the Undo buffer
Me.gridControl1.CommandStack.Redo.Clear()

Transactions

A Transaction is a series of steps that will be treated as a single action in the Undo/Redo architecture. For example, if a list of operations has been done and undoing these operations in a single click or way is known as Transaction.

Transaction can be done by using the methods BeginTrans, CommitTrans and RollBack in the GridModelCommandManager class.

BeginTrans

A call to CommandStack.BeginTrans will mark the start of a series of actions that are to be treated as a single Undo/Redo step. Once BeginTrans is called, all the changes are marked as being a member of a single transaction until either CommitTrans or RollBack is called. 

// Transaction will be started
this.gridControl1.CommandStack.BeginTrans("Transaction started");
' Transaction will be started
Me.gridControl1.CommandStack.BeginTrans("Transaction started")

After starting the transaction using the above method, do the list of changes in grid so that it will stored as one transaction while committing the transaction using CommitTrans method.

CommitTrans

CommandStack.CommitTrans method will denote the GridControl to stop the transaction and to save all the changes in one transaction. Then this single transaction will be stored in stack.

// Current Transaction will be stopped
this.gridControl1.CommandStack.CommitTrans();
' Current Transaction will be stopped
Me.gridControl1.CommandStack.CommitTrans()

Rollback

A call to CommandStack.Rollback method will cause all the changes in the current transaction to be undone and will end the transaction processing. Rollback call will return the grid to the same state that it was immediately prior to the call to BeginTrans.

// Current Transaction will be stopped and undone
this.gridControl1.CommandStack.Rollback();
' Current Transaction will be stopped and undone
Me.gridControl1.CommandStack.Rollback()

Custom Commands

Undo/Redo methods can be handled manually and not the standard implementation used in Undo/Redo architecture, by using the derived custom commands from the GridModelCommand abstract class. In the derived class, add necessary members to track the Undo/Redo actions.

public class MyCustomCommand : GridModelCommand
{

// Constructor for MyCustomCommand class.
    public MyCustomCommand()
    {
    }

// Overrides the Execute method.
    public override void Execute()
    {
    }
}
Public Class MyCustomCommand
Inherits GridModelCommand

'Constructor for MyCustomCommand class.
Public Sub New()
End Sub

'Overrides the Execute method.
Public Overrides Sub Execute()
End Sub
End Class

After creating the GridModelCommand derived class, create a proper instance of your derived GridModelCommand class and add it to CommandStack.UndoStack whenever the action is taken.

Creating Custom Commands for Covered Cells

To create a custom command on making the undo/redo operations for covered ranges cells, make use of the below code which explains a simple way on achieving it.

The GridModelCommand class has an overridden method called Execute. This method will execute the set of codes mentioned in it while the custom undo/redo process goes on.

public class GridModelSetCoveredRangesCommand

: GridModelCommand
{
    GridRangeInfoList ranges;
    bool setOrReset;
    private GridModelCoveredRanges coveredRange;
    public GridModelSetCoveredRangesCommand(GridModelCoveredRanges coveredRange, GridRangeInfoList ranges, bool setOrReset)

    : base(coveredRange.Model)
    {
        if (setOrReset)
        {
            SetDescription("CommandAddCoveredRanges");
        }
        else
        {
            SetDescription("CommandRemoveCoveredRanges");
        }
        this.coveredRange = coveredRange;
        this.ranges = ranges;
        this.setOrReset = setOrReset;
    }

// Executes the command.

public override void Execute()
{
    coveredRange.SetCoveredRanges(ranges, setOrReset);
    Grid.ScrollCellInView(ranges.ActiveRange, GridScrollCurrentCellReason.Command);
}

}
Public Class GridModelSetCoveredRangesCommand
Inherits GridModelCommand
Private ranges As GridRangeInfoList
Private setOrReset As Boolean
Private coveredRange As GridModelCoveredRanges
Public Sub New(ByVal coveredRange As GridModelCoveredRanges, ByVal ranges As GridRangeInfoList, ByVal setOrReset As Boolean)
MyBase.New(coveredRange.Model)
If setOrReset Then
SetDescription("CommandAddCoveredRanges")
Else
SetDescription("CommandRemoveCoveredRanges")
End If

Me.coveredRange = coveredRange

Me.ranges = ranges

Me.setOrReset = setOrReset

End Sub

' Executes the command.

Public Overrides Sub Execute()
coveredRange.SetCoveredRanges(ranges, setOrReset)
Grid.ScrollCellInView(ranges.ActiveRange, GridScrollCurrentCellReason.Command)
End Sub
End Class

After creating the class, add the transaction to the GridControl by using the CommandStack.Push method. Call this method to necessary places in which the users need to make the Undo/Redo operations.

this.gridControl1.CommandStack.Push(new GridModelSetCoveredRangesCommand(this.gridControl1.Model.CoveredRanges, list, false));
Me.gridControl1.CommandStack.Push(New GridModelSetCoveredRangesCommand(Me.gridControl1.Model.CoveredRanges, list, False))

After pushing the custom command unto the stack, if user make any merge cells using the covered ranges then it can be undone by using the Undo method or by keyboard shortcuts.