How to perform undo or redo operation in WinForms GridGroupingControl?
Perform undo or redo operation
Description
WinForms
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.
//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;
}
}'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 Class2. 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.
//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);
}'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 Sub3. 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.
// Handle the undo commands until we change the value back
// (may have current cell 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 swap values 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 swap values 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)
);
}
}
}'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