locked
How to implement undo/redo (enable undo/redo buttons) for ToolWindowPane (PersistedWindowPane) RRS feed

  • Question

  • Hello everybody,

    I have a problem enabling undo/redo buttons in Visual Studio 2005 for a ToolWindowPane , they are still disabled. BUT, if I add Copy/Cut/Paste with the methods below, it works great and the buttons are active and could be catched with my event functions.

    What I have done so far...

    Added ToolWindowPane to Package:

    [ProvideToolWindow(typeof
    
    (PersistedWindowPane), Style = VsDockStyle.Tabbed, Window = "3ae79031-e1bc-11d0-8f78-00a0c9110057"
    
    )]

     

    Enabled Undo/Redo in the ToolWindowPane:

        private void InitMenuCommands()
        {
          IMenuCommandService mcs = this.GetService(typeof(IMenuCommandService)) as IMenuCommandService;
          if (null != mcs)
          {
            addCommand(mcs, StandardCommands.Undo,
                  new EventHandler(onUndo), new EventHandler(onQueryUndo));
            addCommand(mcs, StandardCommands.Redo,
                    new EventHandler(onRedo), new EventHandler(onQueryRedo));
    
    
            addCommand(mcs, StandardCommands.MultiLevelUndo,
                    new EventHandler(onUndo), new EventHandler(onQueryUndo));
            addCommand(mcs, StandardCommands.MultiLevelRedo,
                    new EventHandler(onRedo), new EventHandler(onQueryRedo));
          }
        }
    private void addCommand(IMenuCommandService mcs, CommandID cmdID,
                        EventHandler commandEvent, EventHandler queryEvent)
        {
          OleMenuCommand command = new OleMenuCommand(commandEvent, cmdID);
          // Add an event handler to BeforeQueryStatus if one was passed in
          if (null != queryEvent)
          {
            command.BeforeQueryStatus += queryEvent;
          }
    
          // Add the command using our IMenuCommandService instance
          mcs.AddCommand(command);
        }

    And I have added all the event function for Undo/Redo. I Set a breakpoint in it, but they are not called (Cut/Copy and so on works).
    Also "IOleCommandTarget.QueryStatus" does not receive the Undo/Redo commands, but my ProjectNode does (within "protected override QueryStatusResult QueryStatusCommandFromOleCommandTarget" I receive the Undo/Redo commands, why???).

    I have added the commands (Undo/Redo) to the CMDUSED_SECTION of my CTC file, but it does not help to solve my problem.

    Hope you can help me or give me a hint what to do...

    Thanks,
    Stefan

    • Edited by verdrus Tuesday, February 1, 2011 5:03 PM Removed <br>
    Tuesday, February 1, 2011 4:59 PM

Answers

  • Hello,

     

    I have solved my problem. If you use the UndoManager the MenuCommandService does not work. I have removed following statements from the Class and it works...

    IOleUndoManager _undoManager = (IOleUndoManager)GetService(typeof(SOleUndoManager));
    
          // In order to track when our document returns to the clean state after an undo,
          // we need to Advise for IVsUndoTrackingEvents. This is how the "remove modified 
          // star after undo" feature works.
          IVsChangeTrackingUndoManager changeTrackingUndoMgr = (IVsChangeTrackingUndoManager)_undoManager;
          if (changeTrackingUndoMgr != null)
          {
            changeTrackingUndoMgr.MarkCleanState();
            changeTrackingUndoMgr.AdviseTrackingClient(this);
          }
    
          // In order to use the IVsLinkedUndoTransactionManager, it is required that you
          // advise for IVsLinkedUndoClient notifications. This gives you a callback at 
          // a point when there are intervening undos that are blocking a linked undo.
          // You are expected to activate your document window that has the intervening undos.
          IVsLinkCapableUndoManager linkCapableUndoMgr = (IVsLinkCapableUndoManager)_undoManager;
          if (linkCapableUndoMgr != null)
          {
            linkCapableUndoMgr.AdviseLinkedUndoClient(this);
          }
    

    Thanks,

    Stefan

    • Marked as answer by verdrus Wednesday, February 2, 2011 10:30 AM
    Wednesday, February 2, 2011 10:30 AM

All replies

  • The window frame itself will end up handling Undo/Redo before you ever see them.  It forwards the QueryStatus/Exec to the IOleUndoManager that is associated with your frame, this is the object returned from calling GetService(typeof(IOleUndoManager)).

    Ryan

    Tuesday, February 1, 2011 5:49 PM
  • Is it possible to override these methods?

    My Problem is, that I implement a TreeView as an extension to the solution explorer.  If the user adds or deletes elements in that tree, one or more files are affected (updated), so an undo command needs to undo more than one file at the same time.

    Best regards,
    Stefan

    Wednesday, February 2, 2011 8:52 AM
  • Hello,

     

    I have solved my problem. If you use the UndoManager the MenuCommandService does not work. I have removed following statements from the Class and it works...

    IOleUndoManager _undoManager = (IOleUndoManager)GetService(typeof(SOleUndoManager));
    
          // In order to track when our document returns to the clean state after an undo,
          // we need to Advise for IVsUndoTrackingEvents. This is how the "remove modified 
          // star after undo" feature works.
          IVsChangeTrackingUndoManager changeTrackingUndoMgr = (IVsChangeTrackingUndoManager)_undoManager;
          if (changeTrackingUndoMgr != null)
          {
            changeTrackingUndoMgr.MarkCleanState();
            changeTrackingUndoMgr.AdviseTrackingClient(this);
          }
    
          // In order to use the IVsLinkedUndoTransactionManager, it is required that you
          // advise for IVsLinkedUndoClient notifications. This gives you a callback at 
          // a point when there are intervening undos that are blocking a linked undo.
          // You are expected to activate your document window that has the intervening undos.
          IVsLinkCapableUndoManager linkCapableUndoMgr = (IVsLinkCapableUndoManager)_undoManager;
          if (linkCapableUndoMgr != null)
          {
            linkCapableUndoMgr.AdviseLinkedUndoClient(this);
          }
    

    Thanks,

    Stefan

    • Marked as answer by verdrus Wednesday, February 2, 2011 10:30 AM
    Wednesday, February 2, 2011 10:30 AM
  • I am curious what you mean by 'the MenuCommandService does not work', using the UndoManager doesn't make the Undo/Redo commands go to the MenuCommandService, the Undo/Redo commands will ALWAYS be handled by the IOleUndoManager, never by your code.  The idea is to use the IOleUndoManager to implement your undo/redo stack.  It supports 'compound' undo/redo actions where you do multiple things (like add/remove multiple tree nodes).

    Ryan

    Wednesday, February 2, 2011 4:12 PM