Articles in this section
Category / Section

How to perform undo or redo operation in WinForms GridGroupingControl?

4 mins read

Perform undo or redo operation

Description

GridGroupingControl does not support the Undo or Redo architecture that is provided by the GridControlBase.

Solution

When you want to use the Undo or Redo support, you can add custom commands derived from the abstract GridModelCommand, to manage the actions you want to support. The attached sample shows one way to handle undo or redo on the user changed values.

1. Creating a Custom Command Class:

A class GGCValueChangedCmd is created and inherited from the GridModelCommand class.

C#

//derived command to manage value changed action.
public class GGCValueChangedCmd : GridModelCommand
{
    private object oldValue;
    private object newValue;
    private string fieldName;
    private GridRecordRow record;
    public GGCValueChangedCmd(object newValue, object oldValue, string fieldName, GridRecordRow record)
    {
        this.record = record;
        this.fieldName = fieldName;
        this.oldValue = oldValue;
        this.newValue = newValue;
    }
    //perform the value changing in the execute method.
    public override void Execute()
    {
        this.record.ParentRecord.BeginEdit();
        this.record.ParentRecord.SetValue(fieldName, oldValue);
        this.record.ParentRecord.EndEdit();
    }
    //interchanging the oldvalue and newvalue.
    public void SwapValues()
    {
        object o = this.oldValue;
        this.oldValue = newValue;
        newValue = o;
    }
}

VB

'derived command to manage value changed action.
Public Class GGCValueChangedCmd
    Inherits GridModelCommand
    Private oldValue As Object
    Private newValue As Object
    Private fieldName As String
    Private record As GridRecordRow
    Public Sub New(ByVal newValue As Object, ByVal oldValue As Object, ByVal fieldName As String, ByVal record As GridRecordRow)
        Me.record = record
        Me.fieldName = fieldName
        Me.oldValue = oldValue
        Me.newValue = newValue
    End Sub
    'perform the value changing in the execute method.
    Public Overrides Sub Execute()
    Me.record.ParentRecord.BeginEdit()
        Me.record.ParentRecord.SetValue(fieldName, oldValue)
        Me.record.ParentRecord.EndEdit()
    End Sub
    'interchanging the oldvalue and newvalue.
    Public Sub SwapValues()
        Dim o As Object = Me.oldValue
        Me.oldValue = newValue
        newValue = o
    End Sub
End Class

2. Working with CommandStack

The TableControlCurrentCellValidating is used to cache the old value. TableControlCurrentCellAcceptedChanges event is used to create an instance of the custom command and push it on the CommandStack.

C#

//used to cache old value so it will be easily available in 
//TableControlCurrentCellAcceptedChanges where the GGCValueChangedCmd object needs it.
void gridGroupingControl1_TableControlCurrentCellValidating(object sender, GridTableControlCancelEventArgs e)
{
    GridCurrentCell cc = e.TableControl.GetNestedCurrentCell();
    GridTableCellStyleInfo style = e.TableControl.GetTableViewStyleInfo(cc.RowIndex, cc.ColIndex);
    //Console.WriteLine(style.CellValue);
    oldValue = style.CellValue;
}
//used to generate the undo command and push it on the CommandStack
void gridGroupingControl1_TableControlCurrentCellAcceptedChanges(object sender, GridTableControlCancelEventArgs e)
{
    GridCurrentCell cc = e.TableControl.GetNestedCurrentCell();
    GridTableCellStyleInfo style = e.TableControl.GetTableViewStyleInfo(cc.RowIndex, cc.ColIndex);
    //Console.WriteLine(style.CellValue);
    GGCValueChangedCmd cmd = new GGCValueChangedCmd(style.CellValue, oldValue, style.TableCellIdentity.Column.MappingName, style.TableCellIdentity.DisplayElement as GridRecordRow);    this.gridGroupingControl1.TableControl.Model.CommandStack.Push(cmd);//.UndoStack.Push(cmd);
}

VB

'used to cache old value so it will be easily available in 
'TableControlCurrentCellAcceptedChanges where the GGCValueChangedCmd object needs it.
Private Sub gridGroupingControl1_TableControlCurrentCellValidating(ByVal sender As Object, ByVal e As GridTableControlCancelEventArgs)
    Dim cc As GridCurrentCell = e.TableControl.GetNestedCurrentCell()
    Dim style As GridTableCellStyleInfo = e.TableControl.GetTableViewStyleInfo(cc.RowIndex, cc.ColIndex)
    'Console.WriteLine(style.CellValue);
    oldValue = style.CellValue
End Sub
'used to generate the undo command and push it on the CommandStack
Private Sub gridGroupingControl1_TableControlCurrentCellAcceptedChanges(ByVal sender As Object, ByVal e As GridTableControlCancelEventArgs)
    Dim cc As GridCurrentCell = e.TableControl.GetNestedCurrentCell()
    Dim style As GridTableCellStyleInfo = e.TableControl.GetTableViewStyleInfo(cc.RowIndex, cc.ColIndex)
    'Console.WriteLine(style.CellValue);
    Dim cmd As New GGCValueChangedCmd(style.CellValue, oldValue, style.TableCellIdentity.Column.MappingName, TryCast(style.TableCellIdentity.DisplayElement, GridRecordRow))
    Me.gridGroupingControl1.TableControl.Model.CommandStack.Push(cmd)  '.UndoStack.Push(cmd);
End Sub

3. Performing Undo/Redo operation

The Undo or Redo operations are performed by using buttons. UndoStack and RedoStack of CommandStack are used to retrieve the old or new values accordingly, to perform the undo or redo operation. The Execute() method of GridModelCommand is overridden for reassigning the values to a record. A helper method SwapValues() is used to swap the old or new values.

C#

//handle the undo commands until we change the value back 
//(may have currentcell selection undo commands also) and also push commands onto the Redo stack
private void btn_undo_Click(object sender, EventArgs e)
{
if (this.gridGroupingControl1.TableControl.Model.CommandStack.UndoStack.Count > 0)
{
    GridModelCommand cmd = this.gridGroupingControl1.TableControl.Model.CommandStack.UndoStack.Peek() as GridModelCommand;
    if (cmd != null)
    {
        do
        {
            cmd = this.gridGroupingControl1.TableControl.Model.CommandStack.UndoStack.Pop() as GridModelCommand;
            if (cmd != null)
            {
                cmd.Execute();
                if (cmd is GGCValueChangedCmd)
                {
                    //call the swapvalues method
                    ((GGCValueChangedCmd)cmd).SwapValues();
                }                this.gridGroupingControl1.TableControl.Model.CommandStack.RedoStack.Push(cmd);
            }
        } while (this.gridGroupingControl1.TableControl.Model.CommandStack.UndoStack.Count > 0
                    && cmd != null && !(cmd is GGCValueChangedCmd));
    }
}
}
//handle the redo and push commands back onto the UndoStack
private void btn_redo_Click(object sender, EventArgs e)
{
if (this.gridGroupingControl1.TableControl.Model.CommandStack.RedoStack.Count > 0)
{
    GridModelCommand cmd = this.gridGroupingControl1.TableControl.Model.CommandStack.RedoStack.Peek() as GridModelCommand;
    if (cmd != null)
    {
        do
        {
            cmd = this.gridGroupingControl1.TableControl.Model.CommandStack.RedoStack.Pop() as GridModelCommand;
            if (cmd != null)
            {
                cmd.Execute();
                if (cmd is GGCValueChangedCmd)
                {
                    //call the swapvalues method
                    ((GGCValueChangedCmd)cmd).SwapValues();
                }                this.gridGroupingControl1.TableControl.Model.CommandStack.UndoStack.Push(cmd);
            }
        } while (this.gridGroupingControl1.TableControl.Model.CommandStack.RedoStack.Count > 0 && cmd != null && !(cmd is GGCValueChangedCmd));
    }
}
}

VB

'handle the undo commands until we change the value back. 
'(may have currentcell selection undo commands also) and also push commands onto the Redo stack.
Private Sub btn_undo_Click(ByVal sender As Object, ByVal e As EventArgs)
If Me.gridGroupingControl1.TableControl.Model.CommandStack.UndoStack.Count > 0 Then
    Dim cmd As GridModelCommand = TryCast(Me.gridGroupingControl1.TableControl.Model.CommandStack.UndoStack.Peek(), GridModelCommand)
    If cmd IsNot Nothing Then
        Do
            cmd = TryCast(Me.gridGroupingControl1.TableControl.Model.CommandStack.UndoStack.Pop(), GridModelCommand)
            If cmd IsNot Nothing Then
                cmd.Execute()
                If TypeOf cmd Is GGCValueChangedCmd Then
                    'call the swapvalues method
                    CType(cmd, GGCValueChangedCmd).SwapValues()
                End If
Me.gridGroupingControl1.TableControl.Model.CommandStack.RedoStack.Push(cmd)
            End If
            Loop While
             Me.gridGroupingControl1.TableControl.Model.CommandStack.UndoStack.Count > 0 AndAlso cmd IsNot Nothing AndAlso Not(TypeOf cmd Is GGCValueChangedCmd)
 End If
End If
End Sub
'handle the redo and push commands back onto the UndoStack.
Private Sub btn_redo_Click(ByVal sender As Object, ByVal e As EventArgs)
If Me.gridGroupingControl1.TableControl.Model.CommandStack.RedoStack.Count > 0 Then
 Dim cmd As GridModelCommand = TryCast(Me.gridGroupingControl1.TableControl.Model.CommandStack.RedoStack.Peek(), GridModelCommand)
           If cmd IsNot Nothing Then
               Do
                   cmd = TryCast(Me.gridGroupingControl1.TableControl.Model.CommandStack.RedoStack.Pop(), GridModelCommand)
                   If cmd IsNot Nothing Then
                       cmd.Execute()
                       If TypeOf cmd Is GGCValueChangedCmd Then
                           'call the swapvalues method
                           CType(cmd, GGCValueChangedCmd).SwapValues()
                       End If
                        Me.gridGroupingControl1.TableControl.Model.CommandStack.UndoStack.Push(cmd)
                  End If
                  Loop While         Me.gridGroupingControl1.TableControl.Model.CommandStack.RedoStack.Count > 0 AndAlso cmd IsNot Nothing AndAlso Not(TypeOf cmd Is GGCValueChangedCmd)
            End If
     End If
End Sub

Samples:

C#: Undo_Redo

VB: Undo_Redo

Did you find this information helpful?
Yes
No
Help us improve this page
Please provide feedback or comments
Comments
Please sign in to leave a comment
Access denied
Access denied