在 Visual Studio 旗舰版 中定义 UML 设计器的扩展时,可将多个更改组合成一个名为“链接的撤消上下文”的事务。

默认情况下,代码对模型所做的每个修改都可由用户分别撤消。 例如,如果您定义了用于交换两个 UML 类名称的菜单项,则用户可以调用该命令,然后执行单个撤消。 这将撤消对一个名称所做的更改,但不会撤消另一个名称更改,如此会使您的模型处于非预期状态。

为了避免此问题,代码可在一个事务内执行一系列更改。 这可使这些更改类似于对用户所做的单个更改。 随后的撤消命令将可撤消这一系列更改。

另一个优点是,代码可以通过引发异常或中止事务,撤消一组部分完成的更改。

将多个更改组合成一个事务

确保您的项目引用包括此 .NET 程序集:

Microsoft.VisualStudio.Modeling.Sdk.11.0.dll

在您的类内,声明类型为 ILinkedUndoContext 的导入属性:

using Microsoft.VisualStudio.Modeling.ExtensionEnablement;

...

class … {

[Import]

public ILinkedUndoContext LinkedUndoContext { get; set; }

在修改模型的方法中,将您的更改包含在一个事务中:

using (ILinkedUndoTransaction transaction =

LinkedUndoContext.BeginTransaction("my updates"))

{

// code to update model elements or shapes goes here

transaction.Commit();

}

注意下列事项:

  • 您必须始终在事务末尾包含 Commit()。 如果在没有提交的情况下释放了事务,则该事务将被回滚。 也就是说,模型将还原为事务开始时的状态。

  • 如果在事务内发生了未捕获的异常,则该事务将被回滚。 将事务的 using 块放入 try…catch 块中是一种常见的模式。

  • 可以嵌套事务。

  • 可以向 BeginTransaction() 提供任何非空白名称。

  • 只有 UML 模型存储区受这些事务影响。 建模事务不影响:变量、如文件和数据库之类的外部存储区、层关系图、从代码生成的序列图以及代码模型。

 示例

    using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
    using Microsoft.VisualStudio.Uml.Interfaces;
    using Microsoft.VisualStudio.Uml.Classes;
    using Microsoft.VisualStudio.Uml.Extensions;
    using System.Linq;
    using System.ComponentModel.Composition;
 ...
  [Import]
  public ILinkedUndoContext LinkedUndoContext { get; set; }

  /// <summary>
  /// Swap the names of the currently selected elements.
  /// </summary>
  public void Execute(IMenuCommand command)
  {
    var selectedShapes =
      Context.CurrentDiagram.GetSelectedShapes<IClassifier>();
    if (selectedShapes.Count() < 2) return;
    IClassifier firstElement = selectedShapes.First().Element;
    IClassifier lastElement = selectedShapes.Last().Element;
    string firstName = firstElement.Name;
    // Perform changes inside a transaction so that undo
    // works as a single change.
    using (ILinkedUndoTransaction transaction = 
      LinkedUndoContext.BeginTransaction("Swap names"))
    {
        firstElement.Name = lastElement.Name;
        lastElement.Name = firstName;
        transaction.Commit();
    }
 }

请参见

概念

使用 UML API 编程

如何:在建模图上定义菜单命令

扩展 UML 模型和关系图