Challenges in implementing the Undo Redo functionality
Here are some of the points to be noted
- Undo/Redo is an EDIT operation
Operation1 + Undo(on Operation1) = 2 Edit operations.
This will mean that the state of the object(lastModified) is changed even though there is no change in the content.
Hence any mechanism to know whether there are any changes made to the ObjectModel state must be based on the difference in the content and cannot just be based on its lastModified info.
- Maintaining the edits in a Stack(FirstInLastOut behaviour) will enforce the undo/redo implementation to be sequential in the reverse order in which the operations were performed. It cannot offer the flexibility to offer the undo/redo functionality for the edits which need not correspond to the latest edit operation.
- Each edit must implement the CanUndo() and CanRedo() to validate the undo/redo operation. This is very essential to ensure that the object model on which edit operation is performed via the undo/redo implementation does not push the underlying object model to an Invalid state.
Each edit might have a cached object instance associated with it when the edit is initialized. When trying to perform the Undo/Redo operation using the cached object, validation is must to ensure that using the cached object doesnt push the underlying object model to an Invalid State, resulting in a total disaster.
- Each edit must implement Dispose() to ensure that objects cached in the edit are disposed and they don’t eat up the memory.
In addition to all these, for a robust implementation of undo/redo here are some tips
1. Undo Redo for an edit operation on the objectModel should only be dependent on the objects in the objectModel. It should never be dependent on the objects used in the UI which are used for displaying the content of the objectModel.
2. Always update the object model before updating the UI, so that the UI displayed will always truly represents the object model.
3. The undo/redo implementation will deal with cached instance of the object model but working with caching instances of the UI objects should be avoided and instead the UI objects which represent the object model must be retreived at run time.