I have used the command pattern
before to give multi-level undo\redo. Depending on your application, this might be overkill. Currently I don't use this becuase I mostly work with ADO.NET datasets which have the RejectChanges method for cancellation.
EDIT: just happened upon http://undo.codeplex.com/ which appears to be a framework for the command pattern (I have not looked in depth yet).