How to: Implement Undo Management
Note
This article applies to Visual Studio 2015. If you're looking for the latest Visual Studio documentation, see Visual Studio documentation. We recommend upgrading to the latest version of Visual Studio. Download it here
The primary interface used for undo management is IOleUndoManager, which is implemented by the environment. To support undo management, implement separate undo units (that is, IOleUndoUnit, which can contain multiple individual steps.
How you implement undo management varies depending on whether your editor supports multiple views or not. The procedures for each implementation are detailed in the following sections.
Cases where an editor supports a single view
In this scenario, the editor does not support multiple views. There is only one editor and one document, and they support undo. Use the following procedure to implement undo management.
To support undo management for a single-view editor
Call
QueryInterface
on theIServiceProvider
interface on the window frame forIOleUndoManager
, from the document view object to access the undo manager (IID_IOLEUndoManager
).When a view is sited into a window frame, it gets a site pointer, which it can use to call
QueryInterface
forIServiceProvider
.
Cases where an editor supports multiple views
If you have document and view separation, then there is normally one undo manager associated with the document itself. All undo units are placed on one undo manager associated with the document data object.
Instead of the view querying for the undo manager, of which there is one for each view, the document data object calls CreateInstance to instantiate the undo manager, specifying a class identifier of CLSID_OLEUndoManager. The class identifier is defined in the OCUNDOID.h file.
When using CreateInstance to create your own undo manager instance, use the following procedure to hook your undo manager into the environment.
To hook your undo manager into the environment
Call
QueryInterface
on the object returned from ILocalRegistry2 forIID_IOleUndoManager
. Store the pointer to IOleUndoManager.Call
QueryInterface
onIOleUndoManager
forIID_IOleCommandTarget
. Store the pointer to IOleCommandTarget.Relay your QueryStatus and Exec calls into the stored
IOleCommandTarget
interface for the following StandardCommandSet97 commands:cmdidUndo
cmdidMultiLevelUndo
cmdidRedo
cmdidMultiLevelRedo
cmdidMultiLevelUndoList
cmdidMultiLevelRedoList
Call
QueryInterface
onIOleUndoManager
forIID_IVsChangeTrackingUndoManager
. Store the pointer to IVsChangeTrackingUndoManager.Use the pointer to IVsChangeTrackingUndoManager to call the MarkCleanState, the AdviseTrackingClient, and the UnadviseTrackingClient methods.
Call
QueryInterface
onIOleUndoManager
forIID_IVsLinkCapableUndoManager
.Call AdviseLinkedUndoClient with your document, which should also implement the IVsLinkedUndoClient interface. When your document is closed, call
IVsLinkCapableUndoManager::UnadviseLinkedUndoClient
.When your document is closed, call
QueryInterface
on your undo manager forIID_IVsLifetimeControlledObject
.Call SeverReferencesToOwner.
When changes are made to the document, call Add on the manager with an
OleUndoUnit
class. The Add method keeps a reference to the object, so generally you release it right after the Add.The
OleUndoManager
class represents a single undo stack instance. Thus, there is one undo manager object per data entity being tracked for undo or redo.
Note
While the undo manager object is used extensively by the text editor, it is a general component that has no specific support for the text editor. If you want to support multi-level undo or redo, you can use this object to do so.
See Also
IVsChangeTrackingUndoManager
IVsLifetimeControlledObject
How to: Clear the Undo Stack