Question

I have written a Visual Studio extension and I have it keep a log of user actions related to my extension. I want to be able to include undo/redo information for changes that my tool makes in the log, which I expect to be able to do by having an event listener called when an undo/redo occurs and check if the undo/redo object is the one corresponding to an action that my tool generated.

Currently, I have code to get the ITextUndoHistory for the current IWpfTextView, which I get using an ITextUndoHistoryRegistry which I followed this answer to generate. Unfortunately, the ITextUndoHistory object I get does not implement enough of the functionality to be useful. Specifically, its UndoRedoHappened event gets called, but always has a transaction of null. Also, its UndoStack/RedoStack properties throw System.NotSupportedException. The only thing that does work is CreateTransaction does give me a transaction object and lets me set the name for the action displayed in Visual Studio's undo/redo list, although I don't need that to work.

Is there some other way to access undo information in Visual Studio? Or maybe some more creative hack with what I have access to?

Was it helpful?

Solution

I'm assuming you're wanting to log undo/redos of commands of your editor extension. If that's not the case...this description below won't be useful. :-)

What you want to do first is create a small class that derives from ITextUndoPrimitive which represents a small "operation" that's included in a part of a undo transaction. This has two important methods: Undo() which is called when the user undoes the transaction, and Do() which is called if the user undid the transaction and then hit Redo. For the rest of the methods, just do the trivial implementation: CanUndo/CanRedo should always return true, and make Parent a simple read/write property. CanMerge should always return false, and you can leave Merge() unimplemented. You can of course hold any additional state you want in the ITextUndoPrimitive.

As far as what you do in Do/Undo, that's up to you. So if your extension is, say, modifying the text buffer and also writing to some other file in the user's project, you could undo the file write. I get a sense you're just trying to track which operations the user undid (perhaps for statistical purposes?), and so you might just update a "the user undid this" bit in your log and be done with it.

When you are performing your action, call CreateTransaction to start a new transaction, and then on that transaction call AddUndo() passing in a new instance of your undo primitive. The editor will then call Do/Undo as described as appropriate.

One last note: the editor will automatically get rid of undo transactions when either the transaction history is getting too long, or in some cases where the history is destroyed and it must be reset. So expect that at some point your undo primitives will go away and be GC'ed. Most importantly: don't hold onto them in some other place that would cause them to leak.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top