【问题标题】:How to manage undo/redo stack in VSPackage?如何管理 VSPackage 中的撤消/重做堆栈?
【发布时间】:2012-05-07 19:58:28
【问题描述】:

我创建了在 Visual Studio 代码窗口上下文菜单中提供某些功能的 VSPackage。这个动作包括几个代码编辑和一些周围的东西。

问题是,这些代码编辑中的每一个都被分别添加到撤消堆栈中。我想要的是将此操作作为一个原子单元来处理,即按 CTRL+Z 回滚所有代码编辑和其他所有内容(当然,还要将该单元放在重做堆栈的顶部)。

关于这个主题的文档非常少,我唯一发现的是关于 IOleParentUndo 单元的东西 - 但我没有成功实施它。

我用

IVsTextLines.GetUndoManager()

获取撤消管理器 - 这似乎是一个好的开始。

【问题讨论】:

    标签: c# vsx vspackage


    【解决方案1】:

    如果撤消是在文档级别进行管理的,那么您可能必须使用 RunningDocumentTable 来枚举表,获取它们的撤消管理器,然后从轨道中删除:

    class NavigateListener: IVsRunningDocTableEvents3
    {
        private HashSet<IVsTextView> views = new HashSet<IVsTextView>();
        private IVsRunningDocumentTable table;
        private uint cookie;
    ...
    

    在外面,调用这个注册调用——添加一个取消通知事件的取消注册调用。

    public void Register()
    {
        table =(IVsRunningDocumentTable)    Package.GetGlobalService(typeof(SVsRunningDocumentTable));
        // Listen to show/hide events of docs to register activate/deactivate cursor  listeners.
        table.AdviseRunningDocTableEvents(this, out cookie);
    }
    

    运行表有很多事件,比如save等,但是你可以在注册视图时监听:

    public int OnAfterDocumentWindowHide(uint docCookie, IVsWindowFrame pFrame)
    {
        IVsTextView view = VsShellUtilities.GetTextView(pFrame);
        if (view != null)
        {
            views.Add(view);
        }
    }
    

    您可能在处理已保存更改但随后关闭的文档时遇到问题...暂时将其删除...

    public int OnBeforeDocumentWindowShow(uint docCookie, int fFirstShow, IVsWindowFrame pFrame)
    {
        IVsTextView view = VsShellUtilities.GetTextView(pFrame);
        if (view != null)
        {
            views.Remove(view);
        }
        return VSConstants.S_OK;
    }
    

    然后你可以做一个超级撤消核弹。我没有测试这部分——你必须玩它。

    private void NukeFromOrbit()
    {
        foreach( var view in views )
        {
            IVsTextLines buffer;
            view.GetBuffer(out buffer);
            IOleUndoManager manager;
            buffer.GetUndoManager(out manager);
            IEnumOleUndoUnits units;
            manager.EnumUndoable(out units);
            uint fetched=0;
            var unitArray = new IOleUndoUnit[1];
            while( units.Next(1, unitArray , out fetched ) == VSConstants.S_OK)
            {
                unitArray[0].Do(manager);
            }
        }
    }
    

    【讨论】:

    • 我自己确实想出了这样的解决方案 - 但很高兴知道没有比这更好的了,谢谢 :-)
    【解决方案2】:

    尝试使用这样的东西:

    IDesignerHost host = ...;
    DesignerTransaction transaction = host.CreateTransaction("Command Name");
    try
    {
      // Command Body
      TypeDescriptor.GetProperties(control)["Location"].SetValue(control, location);
      transaction.Commit();
    }
    catch
    {
        transaction.Cancel();
        throw;
    }
    

    【讨论】:

    • 对不起,我没听懂。什么是“控制”?什么是“位置”?这对撤消堆栈有什么作用?
    • 这是我在 Design Surface 上执行某些操作时使用事务的方式。我得到主机然后打开事务然后在表面上编辑控件然后提交事务。
    • 你可以以我的项目为例http://sourceforge.net/projects/reportdesinerex/
    【解决方案3】:

    我封装了下面的代码来撤消几个操作。

    public class VSUndo : IDisposable
    {
        public static UndoContext undoContext;
    
        public static VSUndo StartUndo()
        {
            undoContext = ((DTE2)Package.GetGlobalService(typeof(DTE))).UndoContext; 
            undoContext.Open(Guid.NewGuid().ToString());
            // return new instance for calling dispose to close current undocontext
            return new VSUndo(); 
        }
    
        public void Dispose()
        {
            undoContext.Close();
        }
    
    }
    

    那么,你可以使用:

    using (VSUndo.StartUndo())
    {
       // couple of actions that may need to undo together
    }
    

    【讨论】:

      猜你喜欢
      • 2023-03-10
      • 2021-06-04
      • 1970-01-01
      • 1970-01-01
      • 2017-03-16
      • 2010-12-21
      • 1970-01-01
      • 2021-03-05
      • 2018-09-12
      相关资源
      最近更新 更多