none
如何得知一个DesignerTransaction被撤销了? RRS feed

  • 问题

  • 我手头有两个Component,分别叫Tester和Target,此外为Tester提供了一个ComponentDesigner。TesterComponentDesigner暴露了一个Verb,这个Verb的动作是:

    1. 创建一个叫“Add Target”的DesignerTransaction,在这里面使用DesignerHost创建一个Target并添加到Form上面;

    2. 将第一步创建的Target保存下来供后续使用。

    这个Verb能够正确执行,DesignerTranscation能保存在Undo List中,并且在Form上能够正确的Undo/Redo。不过我发现:当这个DesignerTransaction被Undo时,仅仅是在Form Designer上把Target拿掉了,TestComponentDesigner内保存的那个依然还在。

    我尝试以下方法去获取与undo相关的事件,均无功而返:

    1. 通过GetService取得UndoEngine并挂接Undoing事件,发现不管是在Undo还是Redo时都能收到,而事件发生时通过DesignerHost的TransactionDescription拿回来的是空字符串,事件本身也没有提供信息说明undo的是什么;

          private void HookUndoEngineEvent()
          {
             if (m_UndoEngine != null) return;
    
             m_UndoEngine = (UndoEngine)GetService(typeof(UndoEngine));
             if (m_UndoEngine != null)
             {
                MessageBox.Show("UndoEngine Retrieved.");
    
                m_UndoEngine.Undoing += OnUndoing;
             }
          }
    
          private void OnUndoing(object sender, EventArgs e)
          {
             IDesignerHost designerHost = (IDesignerHost)GetService(typeof(IDesignerHost));
             if (designerHost != null)
             {
                MessageBox.Show("Undoing: " + designerHost.TransactionDescription);
             }
          }

    2. 挂接EnvDTE.Events.CommandEvents中的undo相关的事件,发现这些事件好像并没有发出来;

          private void HookDTEUndoEvent()
          {
             if (m_CommandEventsUndo != null) return;
    
             DTE dte = (DTE)Marshal.GetActiveObject("VisualStudio.DTE.10.0");
             if (dte != null)
             {
                MessageBox.Show("DTE Retrieved.");
    
                // VSStd97CmdID.Undo
                m_CommandEventsUndo = dte.Events.CommandEvents["{5EFC7975-14BC-11CF-9B2B-00AA00573819}", 43];
    
                // VSStd97CmdID.MultiLevelUndo
                //m_CommandEventsUndo = m_DTE.Events.CommandEvents["{5EFC7975-14BC-11CF-9B2B-00AA00573819}", 44];
    
                // VSStd2KCmdID.UNDO
                //m_CommandEventsUndo = m_DTE.Events.CommandEvents["{1496A755-94DE-11D0-8C3F-00C04FC2AAE2}", 71];
    
                // VSStd2KCmdID.GlobalUndo
                //m_CommandEventsUndo = m_DTE.Events.CommandEvents["{1496A755-94DE-11D0-8C3F-00C04FC2AAE2}", 2138];
    
                if (m_CommandEventsUndo != null)
                {
                   m_CommandEventsUndo.BeforeExecute += BeforeExecuteUndo;
                   m_CommandEventsUndo.AfterExecute += AfterExecuteUndo;
                }
             }
          }
    
          private void BeforeExecuteUndo(string Guid, int ID, object CustomIn, object CustomOut, ref bool bCancel)
          {
             MessageBox.Show(Guid + "\n" + ID.ToString() + "\n" + CustomIn.GetType().ToString() + "\n" + CustomOut.GetType().ToString());
          }
    
          private void AfterExecuteUndo(string Guid, int ID, object CustomIn, object CustomOut)
          {
             MessageBox.Show(Guid + "\n" + ID.ToString() + "\n" + CustomIn.GetType().ToString() + "\n" + CustomOut.GetType().ToString());
          }

    我的问题是:如何才能得到通知说这个DesignerTransaction被undo了,这样才能将TesterComponentDesigner中保存的那个对象清理掉。







    • 已编辑 li-zhe 2013年1月5日 9:06
    • 已移动 Lisa Zhu 2013年1月7日 3:02 (发件人:Visual C#)
    2013年1月5日 7:55

全部回复

  • li-zhe 你好,

    从你的问题描述来看,.NET Framework 一般性问题讨论区更适合来解决这个问题。所以我会将其移过去。

    感谢你的理解与支持。


    Lisa Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2013年1月7日 3:02
  • Hi Li-zhe,

    Undo 是一个user action。我个人觉得你可以在call这个action的时候,将最后一个component从AssociatedComponents 中移除。

    谢谢。


    Mike Feng
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2013年1月7日 11:38
    版主
  • Hi Mike,

    我不是很理解你说的user action的意思,你是指.NET中有对应user action的utility呢,还是建议我用command模式来自行管理?

    Anyway,这部分有点偏离了我目前面临的问题:

    我感觉Visual Studio会针对每一个Editor去维护属于这个Editor的Undo List。对于某些Editor来说,这个Undo List中的某些项可能与其他的Editor的Undo List的某些项有关联,比如窗体设计器和该窗体对应的xxx.Designer.cs文件的编辑器。

    对于我的组件的宿主窗体来说,在某个时间,其对应的Form Designer的Undo List中可能有很多条目,有些是我的组件发出的D4esignerTransaction,有些不是。因此,在每一次undo时,我需要确切的知道:当前正在undo什么,进一步再看当前是否在undo一个DesignerTransaction,如何得到这个DesignerTransaction相关的描述,用这个描述和我内部的记录做比对检查是否是由我的组件发出的,如果是则进行内部的一些undo操作。



    • 已编辑 li-zhe 2013年1月7日 17:07
    2013年1月7日 17:05