Download sample code.
In our recent .NET 2.0 GUI project our client ingenuously asked us to implement undo and redo facility. Nothing unusual nowadays, however it's still not the easiest thing in the world to implement.
Naturally you want to have this feature for a free. You do not want to invest too much time to support it. We had no much time to implement this "sugar" also. I know, I know, this is important for a user, however when you're facing a big project with a lot of logic to be implemented in short time you're starting to think it would be nice to have undo and redo logic that works independently (at least almost independently) on business logic.
Thus, what's that place where we could plug this service? - Exactly! - It's data binding layer.
When you're binding your data to controls the "Type Descriptor Architecture" is used to retrieve and update the data. Fortunately this architecture is allowing us to create a data wrapper (ICustomTypeDescriptor). Such wrapper should track property modifications of the data object thus providing undo and redo service. In short that's all, other are technical details.
Let's look at how undo and redo service goes into the action. Instead of:
bindingSource.DataSource = data;
you have to write:
bindingSource.DataSource = Create-UndoRedo-Wrapper(data);
There should also be a class to collect and track actions. User should create an instance of this class to implement the simplest form of code with undo and redo support:
// Create UndoRedoManager.
undoRedoManager = new UndoRedoManager();
// Create undo and redo wrapper around the data object.
// Bind controls.
new UndoRedoTypeDescriptor(data, undoRedoManager);
Now turn our attention to the implementation of the undo and redo mechanism. There are two types in the core: UndoRedoManager and IAction. The first one is to track actions, the later one is to define undo and redo actions. UndoRedoManager performs either "Do/Redo", or "Undo" operations over IAction instances. We have provided two useful implementations of the IAction interface: UndoRedoTypeDescriptor - wrapper around an object that tracks property changes, and UndoRedoList - wrapper around the IList that tracks collection modifications. Users may create their implementations of the IAction to handle other undo and redo activities.
We have created a sample application to show undo and redo in action. You can download it from here.