2012-05-07 3 views
3

Я создал VSPackage, который обеспечивает определенную функциональность в контекстном меню окна кода Visual Studio. Это действие состоит из нескольких изменений кода плюс некоторые вещи вокруг.Как управлять стоп-кадром/повтором в VSPackage?

Проблема заключается в том, что каждый из этих изменений кода добавляется к столу отмены отдельно. Я хочу обработать это действие как один атомный блок, т. Е. Нажатие CTRL + Z отменяет все изменения кода и все остальное (плюс, конечно, помещает блок поверх стека повтора).

Документация по этой теме крайне бедна, единственное, что я нашел, это что-то вроде единицы IOleParentUndo, но я не был успешным в ее реализации.

Я использую

IVsTextLines.GetUndoManager() 

, чтобы получить менеджер отката - который, кажется, хорошее начало.

ответ

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

Я на самом деле придумал таким решением самого - но это здорово знать, что нет ничего лучше, спасибо :-) – cre8or

+0

+1 для эпического имени методы! – akuhn

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; 
} 
+0

Прости, что не понимаю. Что такое «контроль»? Что такое «местоположение»? Что это делает со стеком отмены? – cre8or

+0

Вот как я использую транзакцию, когда делаю некоторые действия на Design Surface. Я получаю хост, затем открываю транзакцию, затем редактирую элементы управления на поверхности, а затем фиксирую транзакцию. –

+0

Вы можете увидеть мой проект в качестве примера [http://sourceforge.net/projects/reportdesinerex/](http://sourceforge.net/p/reportdesinerex/code/44/tree/) –

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 
}