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