规则在模型内部传播更改

在可视化可以创建存储规则传播从一个元素的更改为另一个和建模 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();
   }
 }
}

备注

规则的代码只应更改状态在存储内的元素,即规则应更改模型元素、关系、形状、连接、关系图,也只有其属性。如果您要将对资源进行的更改在存储外,请定义存储事件。有关更多信息,请参见事件处理程序在模型外部传播更改

定义规则

  1. 定义规则作为类的前缀。 RuleOn 属性。 属性关联规则与某个域类、关系或关系图元素。 规则将应用于此类每个实例,能是抽象的。

  2. 注册规则通过将它添加到域模型类的 GetCustomDomainModelTypes() 设置的返回值。

  3. 从一个抽象规则类派生规则类和写入执行方法的代码。

以下几节更详细地描述了这些步骤。

若要定义在字段的规则类中

  • 在自定义代码文件中,定义类并将其前缀与 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 项目。

编写规则的代码

  • 从以下某个基类派生规则类:

    基类

    触发器

    AddRule

    组件、链接或形状添加。

    除了新元素外,使用该检测新关系,。

    ChangeRule

    更改字段值。 方法参数提供的旧值和新值。

    对于形状,此规则会触发,当内置 AbsoluteBounds 属性更改时,因此,如果形状移动。

    在大多数情况下,重写 OnValueChanged 或 OnValueChanging 在属性处理程序会更方便。 这些方法调用之前直接和更改之后的。 相反,规则通常运行在事务末尾。 有关更多信息,请参见 域属性值更改处理程序

    说明说明
    ,当 LINK 创建或删除时,此规则不会触发。相反,编写 AddRule 和 DeleteRule 域关系的。

    DeletingRule

    触发,当元素或链接将被删除。 属性 ModelElement.IsDeleting 为 true 直到该事务的末尾。

    DeleteRule

    执行,当元素或链接已删除。 规则执行,在其他规则执行后,包括 DeletingRules。 ModelElement.IsDeleting 是错误的,因此, ModelElement.IsDeleted 为 true。 若要允许随后请取消,则组件从内存实际上不会移除,但是,它从 Store.ElementDirectory 中移除。

    MoveRule

    元素从一个存储分区移动到另一个。

    (请注意这与图形形状的位置无关。)

    RolePlayerChangeRule

    此规则仅适用于域关系。 ,如果您显式分配一个模型元素指向链接,的任何一端已被触发。

    RolePlayerPositionChangeRule

    触发使用在链接,的 MoveBefore 或 MoveToIndex 方法时,排序来回元素的链接进行更改。

    TransactionBeginningRule

    执行,在事务中创建。

    TransactionCommittingRule

    执行,则该事务将被提交。

    TransactionRollingBackRule

    执行,则该事务将被回滚。

  • 每个类可以重写的方法。 键入在类的 override 发现它。 此方法的参数标识要更改的元素。

以下几点规则的通知:

  1. 设置在事务中的更改可能触发多个规则。 通常,那么,当在最外层的事务提交时,这些规则执行。 按未指定的顺序执行。

  2. 规则始终是在事务内。 因此,不必创建新的事务进行更改。

  3. 规则,不会执行在事务回滚时,或者,在撤消或重做操作执行时。 这些操作重置存储的所有内容到以前的状态。 因此,因此,如果规则更改任何内容的状态在存储外,它与存储目录的同相可能不会保留。 若要更新在存储外的状态,使用事件最好。 有关更多信息,请参见 事件处理程序在模型外部传播更改

  4. ,在设计从文件时,加载某些规则执行。 若要确定加载或保存是否正在进行,请使用 store.TransactionManager.CurrentTransaction.IsSerializing。

  5. 如果规则的代码创建多个规则触发器,它们将添加到激发的末尾列出并执行,在事务完成之前。 DeletedRules 在其他规则在以后执行。 一个规则可以运行在事务中多次,每项更改的一次。

  6. 来回转换规则若要通过信息,可以在 TransactionContext可以存储信息。 这是在事务中维护的字典。 ,在事务末尾,它被释放。 在每个规则的事件参数提供对它。 确保规则未按可预测的顺序执行。

  7. 在考虑其他选择之后使用规则。 例如,因此,如果要更新属性,该值更改时,请考虑使用一个计算的属性。 如果要约束形状的大小或位置,请使用 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();
    }
  }

}

请参见

概念

事件处理程序在模型外部传播更改

BoundsRules 约束形状位置和大小