- Download undoredosamplezip
The usual rules apply, the download needs to be renamed from .doc to .zip.
I apologise that it’s been a while since I last blogged, but I've been busy working on an MVVM framework and it’s been eating up a lot of time – it’s good eat, but it is time consuming. One of the things I've been adding into the code is the ability to handle undo/redo functionality in a
ViewModel; and more importantly, coordinating undo/redo across multiple View Models. In this blog post, I'd like to demonstrate how easy it is to add this functionality to properties that support change notification. In a future blog, I'll be demonstrating how to extend this to supporting
ObservableCollections as well.
The first thing that we're going to do is define a simple undo/redo interface. Here it is, in all its glory:
Now, we need to create a class that implements this interface.
This class simply wraps a property. Whenever Undo is called, reflection is used to set the property back to its prechanged value. Calling Redo reverses this change. Now, that’s all well and good, but we need to keep track of these changes and apply them – and more importantly, we need to apply them across
ViewModels. This is where the
UndoManager comes in:
In this code, we have two lists – the undoable list and the redoable list. These lists wrap up the
IUndoRedo interface we defined earlier and will actually handle calling Undo or Redo as appropriate. There’s a little wrinkle when you call Undo – we need to copy the Redo list out to a temporary copy so that we can add it back later on. The way that the undo works, is to extract the last item from the undo stack – which then gets removed. This item is put onto the redo stack so that we can redo it later if need be. If you notice, in the
Add method, we clear the Redo stack so that we can’t perform a Redo after a
new operation. As the property gets updated and triggers the
Add method, we have to copy the Redo out, and add it back in after the
Add has been performed.
All you need to do now, is wire your
ViewModel up to the
UndoManager and Robert’s your mother's brother. I’ve attached a sample application which demonstrates this in action – this application isn’t finished yet as we're leaving room for the next installment, where we hook into an undoable observable collection. Here’s a screenshot of the application in action: