MindFusion.Wpf Pack Programmer's Guide
Subclassing the Command Class

Diagramming for WPF diagrams can be just a part of the data model of your application, which might already have undo/redo functions implemented for its native data. To integrate Diagramming for WPF undo functionality into the application's undo mechanism, use the ActionRecorded event. When the event is fired, add a corresponding wrapper-record to your application's history from the event handler. The wrapper could just call Undo and Redo methods of the UndoManager. In such situations make sure the Diagramming for WPF's history Capacity is at least as big as your application's.

Another possibility is to reuse Diagramming for WPF's undo functionality by subclassing Command and creating classes responsible for changes in your application's data. When a change occurs outside the diagram, it can still be recorded by the Diagram's ExecuteCommand method and integrated into Diagramming for WPF's command history.

A simpler scenario when you might have to subclass Command is using complex objects as tags or embedding controls in ControlNode instances. Actions that change these objects or controls cannot be detected and handled automatically by Diagramming for WPF. To integrate such an action into the diagram's undo history, you must create a Command instance that knows how to carry out, undo or redo the action.

Command subclasses must implement Execute, Undo and Redo methods. Actions represented by your subclass must be carried out by executing the ExecuteCommand method of Diagram. ExecuteCommand invokes Execute on the command passed as argument, which is then added to the history queue and whose Undo and Redo methods can be called multiple times later by the undo manager. Usually you can implement Redo as a call to Execute, but if the latter is time consuming, its result state can be saved in an instance member and restored by Redo.

Do not call the Undo and Redo methods of your class directly, just implement them and they will be invoked by UndoManager's Undo or Redo methods when necessary.

The example below shows a simple implementation of Command methods:

C#  Copy Code

public class PersonTag
{
    public string Name;
    public string Address;

    // And so on
    ...
}

public class AddressChangeCmd : Command
{
    public AddressChangeCmd(PersonTag p, string address) :
        base("Address change")
    {
        this.p = p;
        this.oldAddress = p.Address;
        this.newAddress = address;
    }

    public override void Execute(bool undoEnabled)
    {
        p.Address = newAddress;
    }

    public override void Undo()
    {
        p.Address = oldAddress;
    }

    public override void Redo()
    {
        // Undo manager is enabled if Redo is called
        // so pass true for the undoEnabled argument
        Execute(true);
    }

    private PersonTag p;
    private string oldAddress;
    private string newAddress;
}

...

// Somewhere in later code
PersonTag tag = (PersonTag)diagram. ActiveItem.Tag;
AddressChangeCmd cc = new AddressChangeCmd(tag, "far far away");
diagram.ExecuteCommand(cc);

Visual Basic  Copy Code

Public Class PersonTag

    Public Name As String
    Public Address As String

    ' And so on
    ...

End Class

Public Class AddressChangeCmd
    Inherits Command

    Public Sub New(ByVal p As PersonTag, ByVal address As String)

        MyBase.New("Address change")

        Me.p = p
        Me.oldAddress = p.Address
        Me.newAddress = address

    End Sub

    Protected Overrides Sub Execute(ByVal undoEnabled As Boolean)

        p.Address = newAddress

    End Sub

    Protected Overrides Sub Undo()

        p.Address = oldAddress

    End Sub

    Protected Overrides Sub Redo()

        ' Undo manager is enabled if Redo is called
        ' so pass true for the undoEnabled argument
        Execute(True)

    End Sub

    Private p As PersonTag
    Private oldAddress As String
    Private newAddress As String

End Class

...

' Somewhere in later code
Dim tag As PersonTag = CType(diagram.ActiveItem.Tag, PersonTag)
Dim cc As AddressChangeCmd = New AddressChangeCmd(tag, "far far away")
diagram.ExecuteCommand(cc)