Memento

Lots of real world applications need to implement undo/redo. However, most applications written in MVVM lack this feature because it is very hard to implement. Luckily, Catel solves this issue by introducing the IMementoService. The IMementoService is a service that allows a developer to register custom actions that should be undone. A few actions you can think of:

  • Property change of a model
  • Item is added or removed to/from a collection
  • A method is executed

One way to introduce the memento pattern is by creating a copy of the whole memory at each step (yes, some people actually do this), but in Catel it is done a bit smarter. For each possible action type, there is an implementation of the UndoBase. This way, each action will know by itself how to undo or redo. Catel offers the following default implementations:

  • PropertyChangeUndo
  • CollectionChangeUndo
  • ActionUndo

If there are more actions supported, it is possible to write a custom UndoBase implementation and add the specific action to the IMementoService. It will automatically be added to the undo/redo action stack.

Undo and redo support

The IMementoService supports both undo and redo actions. This means that an action that is undo-ed by a call to the Undo method, it is automatically added to the redo stack when redo is supported.

To undo an action, use the code below:

var mementoService = ServiceLocator.Default.ResolveType<IMementoService>();
mementoService.Undo();

It is possible to check whether it is possible to undo actions by using the CanUndo property. This check is not required since the Undo method will also check this internally.

To redo an action, use the code below:

var mementoService = ServiceLocator.Default.ResolveType<IMementoService>();
mementoService.Redo();

It is possible to check whether it is possible to redo actions by using the CanRedo property. This check is not required since the Redo method will also check this internally.

Grouping actions in batches

The MementoService automatically wraps all actions in batches. Because each action is treated as a batch, it is easy to begin a batch and add several actions to a single batch. Below is the code to create a batch:

var mementoService = ServiceLocator.Default.ResolveType<IMementoService>();
mementoService.BeginBatch("Batch title", "Batch description");

// All actions added to the memento service are added to the specified batch

Note that the Title and Description are optional. They are however a great way to represent the batches in the user interface

A batch can be ended in several ways:

  1. A call to EndBatch
  2. A call to BeginBatch

As soon as a batch is ended by one of the ways described below, it will be added to the undo stack.

Ignoring support for memento

Ignoring specific properties or methods for the IMementoService is very easy. Just decorate them with the IgnoreMementoSupportAttribute as shown below:

[IgnoreMementoSupport]
public string IgnoredProperty { get; set; }