更新形状和连接线以反映模型

在 Visual Studio的域特定语言 (dsl),可以这次使外观形状反映基础模型的状态。

应将本主题中的代码示例到 Dsl 项目的一 .cs 文件。在每个文件需要这些语句:

using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;

设置形状属性映射控件的可见性修饰器

您可以控制修饰器的可见性,而无需编写程序代码,通过配置映射在形状和字段类之间在 DSL 定义。有关更多信息,请参见下列主题:

显示形状的颜色和样式作为属性

在 DSL 定义,右击形状类,指向 将显示,然后单击其中一个项 (如 填充颜色

形状现在可以将程序代码或作为用户的一个字段的特性。例如,设置为在命令或规则的程序代码中,可以编写:

shape.FillColor = System.Drawing.Color.Red;

如果您只希望让属性变量在程序管理且不受用户,选择新字段的特性 (如 DSL 定义关系图的 填充颜色 。然后,在 " 属性 " 窗口中,将 可浏览的 到 false 或设置 是只读的 UI 到 true。

定义更改规则使颜色,样式或位置取决于模型元素的属性

您可以定义更新外观模型的其他部分的形状从属项的规则。例如,您可以定义在更新其模型元素的属性的形状从属项的颜色的模型元素的更改规则。有关更改规则的更多信息,请参见 规则在模型内部传播更改

您应使用规则只更新存储区中维护的属性,,因为规则,不会调用在取消命令执行时。这不包括某个图形功能 (如形状的大小和可见性。若要更新形状的函数,请参见 更新非存储图形功能。

下面的示例假定,将显示了 FillColor 作为字段的特性如上一节中所述。

[RuleOn(typeof(ExampleElement))]
  class ExampleElementPropertyRule : ChangeRule
  {
    public override void ElementPropertyChanged(ElementPropertyChangedEventArgs e)
    {
      base.ElementPropertyChanged(e);
      ExampleElement element = e.ModelElement as ExampleElement;
      // The rule is called for every property that is updated.
      // Therefore, verify which property changed:
      if (e.DomainProperty.Id == ExampleElement.NameDomainPropertyId)
      {
        // There is usually only one shape:
        foreach (PresentationElement pel in PresentationViewsSubject.GetPresentation(element))
        {
          ExampleShape shape = pel as ExampleShape;
          // Replace this with a useful condition:
          shape.FillColor = element.Name.EndsWith("3") 
                     ? System.Drawing.Color.Red : System.Drawing.Color.Green;
        }
      }
    }
  }
  // The rule must be registered:
  public partial class OnAssociatedPropertyExptDomainModel
  {
    protected override Type[] GetCustomDomainModelTypes()
    {
      List<Type> types = new List<Type>(base.GetCustomDomainModelTypes());
      types.Add(typeof(ExampleElementPropertyRule));
      // If you add more rules, list them here. 
      return types.ToArray();
    }
  }

使用 OnChildConfigured 初始化形状的属性

设置形状的属性,则首次创建,该关系图类的分部定义的重写 OnChildConfigured() 。关系图类在 DSL 定义指定,因此,生成的代码在 Dsl\Generated Code\Diagram.cs。例如:

  partial class MyLanguageDiagram
  {
    protected override void OnChildConfigured(ShapeElement child, bool childWasPlaced, bool createdDuringViewFixup)
    {
      base.OnChildConfigured(child, childWasPlaced, createdDuringViewFixup);
      ExampleShape shape = child as ExampleShape;
      if (shape != null) 
      {
        if (!createdDuringViewFixup) return; // Ignore load from file.
        ExampleElement element = shape.ModelElement as ExampleElement;
        // Replace with a useful condition:
        shape.FillColor = element.Name.EndsWith("3") 
            ? System.Drawing.Color.Red : System.Drawing.Color.Green;
      }
      // else deal with other types of shapes and connectors.
    }
  }

此方法可用于字段的特性和非存储功能,例如形状的大小。

使用 AssociateValueWith() 更新形状的其他功能

对于形状的某些功能,如它是否具有隐藏或连接线的箭样式,则不会显示该功能内置方法作为字段的特性。对于此类功能的更改不受事务策略的控件。因此,更新其使用规则,不适合的,因此,因为规则未调用,当用户执行撤消命令时。

相反,使用 OnAssociatedPropertyChanged,可以更新这些功能。在下面的示例中,连接线的箭样式由一个字段的特性的值在连接线显示关系的控件:

public partial class ArrowConnector // My connector class. 
{
   /// <summary>
    /// Called whenever a registered property changes in the associated model element.
    /// </summary>
    /// <param name="e"></param>
    protected override void OnAssociatedPropertyChanged(VisualStudio.Modeling.Diagrams.PropertyChangedEventArgs e)
    {
      base.OnAssociatedPropertyChanged(e);
      // Can be called for any property change. Therefore,
      // Verify that this is the property we're interested in:
      if ("IsDirected".Equals(e.PropertyName))
      {
        if (e.NewValue.Equals(true))
        { // Update the shape’s built-in Decorator feature:
          this.DecoratorTo = LinkDecorator.DecoratorEmptyArrow;
        }
        else
        {
          this.DecoratorTo = null; // No arrowhead.
        }
      }
    }
    // OnAssociatedPropertyChanged is called only for properties
    // that have been registered using AssociateValueWith().
    // InitializeResources is a convenient place to call this.
    // This method is invoked only once per class, even though
    // it is an instance method. 
    protected override void InitializeResources(StyleSet classStyleSet)
    {
      base.InitializeResources(classStyleSet);
      AssociateValueWith(this.Store, Wire.IsDirectedDomainPropertyId);
      // Add other properties here.
    }
} 

应调用AssociateValueWith() 要注册的每个字段的特性的一次。在调用后,为指定属性的任何更改将调用这些属性的模型元素的任何形状的 OnAssociatedPropertyChanged() 。

调用每个实例的 AssociateValueWith() 并不是必需的。虽然 InitializeResources 是实例方法,它调用将只每个形状类中的一个。