3

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

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

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

我用

IVsTextLines.GetUndoManager()

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

4

3 回答 3

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);
}

运行表有很多事件,如保存等,但您可以在注册视图时进行监听:

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);
        }
    }
}
于 2012-05-23T15:16:29.317 回答
1

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

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
}
于 2012-07-17T09:01:19.260 回答
1

尝试使用这样的东西:

IDesignerHost host = ...;
DesignerTransaction transaction = host.CreateTransaction("Command Name");
try
{
  // Command Body
  TypeDescriptor.GetProperties(control)["Location"].SetValue(control, location);
  transaction.Commit();
}
catch
{
    transaction.Cancel();
    throw;
}
于 2012-06-26T00:44:34.587 回答