规则在模型内部传播更改
在可视化可以创建存储规则传播从一个元素的更改为另一个和建模 SDK (VMSDK)。发生更改。所有元素都存储时,这些规则计划执行,通常,当在最外层的事务提交时。具有规则不同类型的不同种类的事件,如元素添加或删除它。可以附加规则添加到元素、形状或关系图的特定类型。许多内置功能由规则定义:例如,规则确保关系图更新,当模型更改时发生。可以通过添加自定义该域特定语言拥有规则。
即存储规则用于传播存储内的更改 ),到模型元素的更改特别有用、关系、形状或连接及其字段的特性。规则未运行,当用户调用时撤消或重做命令。相反,事务管理器确保存储内容还原为正确的状态。如果您要将对资源进行的更改在存储外,请使用存储事件。有关更多信息,请参见 事件处理程序在模型外部传播更改。
例如,假设要指定,只要用户 (或代码) 创建类型 ExampleDomainClass 的新元素,另一个类型的一个附加元素模型中的另一部分进行创建。您可以编写 AddRule 并将其与 ExampleDomainClass。您将在规则编写代码创建其他元素。
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.Modeling;
namespace ExampleNamespace
{
// Attribute associates the rule with a domain class:
[RuleOn(typeof(ExampleDomainClass), FireTime=TimeToFire.TopLevelCommit)]
// The rule is a class derived from one of the abstract rules:
class MyAddRule : AddRule
{
// Override the abstract method:
public override void ElementAdded(ElementAddedEventArgs e)
{
base.ElementAdded(e);
ExampleDomainClass element = e.ModelElement;
Store store = element.Store;
// Ignore this call if we're currently loading a model:
if (store.TransactionManager.CurrentTransaction.IsSerializing)
return;
// Code here propagates change as required – for example:
AnotherDomainClass echo = new AnotherDomainClass(element.Partition);
echo.Name = element.Name;
echo.Parent = element.Parent;
}
}
// The rule must be registered:
public partial class ExampleDomainModel
{
protected override Type[] GetCustomDomainModelTypes()
{
List<Type> types = new List<Type>(base.GetCustomDomainModelTypes());
types.Add(typeof(MyAddRule));
// If you add more rules, list them here.
return types.ToArray();
}
}
}
说明 |
---|
规则的代码只应更改状态在存储内的元素,即规则应更改模型元素、关系、形状、连接、关系图,也只有其属性。如果您要将对资源进行的更改在存储外,请定义存储事件。有关更多信息,请参见事件处理程序在模型外部传播更改 |
定义规则
定义规则作为类的前缀。 RuleOn 属性。属性关联规则与某个域类、关系或关系图元素。规则将应用于此类每个实例,能是抽象的。
注册规则通过将它添加到域模型类的 GetCustomDomainModelTypes() 设置的返回值。
从一个抽象规则类派生规则类和写入执行方法的代码。
以下几节更详细地描述了这些步骤。
若要定义在字段的规则类中
在自定义代码文件中,定义类并将其前缀与 RuleOnAttribute 属性:
[RuleOn(typeof(ExampleElement), // Usual value – but required, because it is not the default: FireTime = TimeToFire.TopLevelCommit)] class MyRule ...
主题键入第一个参数可以是域类、域关系、形状、链接或关系图。通常,您将规则应用于一个字段类和关系。
FireTime 通常是 TopLevelCommit。这样可确保规则执行,只有在事务的所有主要更改后。选择内联,在更改之后执行规则;并 LocalCommit,执行规则在当前事务 (结束时可能不是最外面的)。还可以设置规则的优先级别影响其排序。队列,但是,这是实现所需的结果一个不可靠的方法。
可以指定一个抽象类作为主题类型。
规则适用于主题类的所有实例。
FireTime 的默认值为 TimeToFire.TopLevelCommit。,当在最外层的事务提交时,这会导致规则执行。另一种方法是 TimeToFire.Inline。这将导致规则在该触发的事件之后执行。
若要注册规则
添加规则类到域模型 GetCustomDomainModelTypes 返回的类型的列表:
public partial class ExampleDomainModel { protected override Type[] GetCustomDomainModelTypes() { List<Type> types = new List<Type>(base.GetCustomDomainModelTypes()); types.Add(typeof(MyAddRule)); // If you add more rules, list them here. return types.ToArray(); } }
如果不确定的域模型类的名称,请查看文件 Dsl\GeneratedCode\DomainModel.cs内
在编写自定义代码文件的此代码在 DSL 项目。
编写规则的代码
从以下某个基类派生规则类:
基类
触发器
组件、链接或形状添加。
除了新元素外,使用该检测新关系,。
更改字段值。方法参数提供的旧值和新值。
对于形状,此规则会触发,当内置 AbsoluteBounds 属性更改时,因此,如果形状移动。
在大多数情况下,重写 OnValueChanged 或 OnValueChanging 在属性处理程序会更方便。这些方法调用之前直接和更改之后的。相反,规则通常运行在事务末尾。有关更多信息,请参见 域属性值更改处理程序。
说明,当 LINK 创建或删除时,此规则不会触发。相反,编写 AddRule 和 DeleteRule 域关系的。触发,当元素或链接将被删除。属性 ModelElement.IsDeleting 为 true 直到该事务的末尾。
执行,当元素或链接已删除。规则执行,在其他规则执行后,包括 DeletingRules。ModelElement.IsDeleting 是错误的,因此, ModelElement.IsDeleted 为 true。若要允许随后请取消,则组件从内存实际上不会移除,但是,它从 Store.ElementDirectory 中移除。
元素从一个存储分区移动到另一个。
(请注意这与图形形状的位置无关。)
此规则仅适用于域关系。,如果您显式分配一个模型元素指向链接,的任何一端已被触发。
触发使用在链接,的 MoveBefore 或 MoveToIndex 方法时,排序来回元素的链接进行更改。
执行,在事务中创建。
执行,则该事务将被提交。
执行,则该事务将被回滚。
每个类可以重写的方法。键入在类的 override 发现它。此方法的参数标识要更改的元素。
以下几点规则的通知:
设置在事务中的更改可能触发多个规则。通常,那么,当在最外层的事务提交时,这些规则执行。按未指定的顺序执行。
规则始终是在事务内。因此,不必创建新的事务进行更改。
规则,不会执行在事务回滚时,或者,在撤消或重做操作执行时。这些操作重置存储的所有内容到以前的状态。因此,因此,如果规则更改任何内容的状态在存储外,它与存储目录的同相可能不会保留。若要更新在存储外的状态,使用事件最好。有关更多信息,请参见 事件处理程序在模型外部传播更改。
,在设计从文件时,加载某些规则执行。若要确定加载或保存是否正在进行,请使用 store.TransactionManager.CurrentTransaction.IsSerializing。
如果规则的代码创建多个规则触发器,它们将添加到激发的末尾列出并执行,在事务完成之前。DeletedRules 在其他规则在以后执行。一个规则可以运行在事务中多次,每项更改的一次。
来回转换规则若要通过信息,可以在 TransactionContext可以存储信息。这是在事务中维护的字典。,在事务末尾,它被释放。在每个规则的事件参数提供对它。确保规则未按可预测的顺序执行。
在考虑其他选择之后使用规则。例如,因此,如果要更新属性,该值更改时,请考虑使用一个计算的属性。如果要约束形状的大小或位置,请使用 BoundsRule。如果需要响应在属性值更改,添加一 OnValueChanged 处理程序添加到属性。有关更多信息,请参见 响应并传播更改。
示例
,在域关系实例化链接两个组件时,下面的示例更新属性。规则将触发不仅,当用户创建关系图中的链接,,而且,如果程序代码创建链接。
使用任务流解决方案模板,若要测试此示例,请创建一个 DSL 并粘贴下面的代码隐藏文件在 DSL 项目。生成并运行解决方案,并在调试项目的示例文件。绘制注释链接在注释形状和流元素之间。在注释的文本变成有关最新元素的已连接到它。
实际上,通常会写 AddRule 的 DeleteRule。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.Modeling;
namespace Company.TaskRuleExample
{
[RuleOn(typeof(CommentReferencesSubjects))]
public class RoleRule : AddRule
{
public override void ElementAdded(ElementAddedEventArgs e)
{
base.ElementAdded(e);
CommentReferencesSubjects link = e.ModelElement as CommentReferencesSubjects;
Comment comment = link.Comment;
FlowElement subject = link.Subject;
Transaction current = link.Store.TransactionManager.CurrentTransaction;
// Don't want to run when we're just loading from file:
if (current.IsSerializing) return;
comment.Text = "Flow has " + subject.FlowTo.Count + " outgoing connections";
}
}
public partial class TaskRuleExampleDomainModel
{
protected override Type[] GetCustomDomainModelTypes()
{
List<Type> types = new List<Type>(base.GetCustomDomainModelTypes());
types.Add(typeof(RoleRule));
return types.ToArray();
}
}
}