Share via


更新圖形和接點來反映模型

在 Visual Studio 中的特定領域語言中,您可讓圖形的外觀反映基礎模型的狀態。

本主題中的程式碼範例應該新增至 Dsl 專案中的 .cs 檔案。 您需要每個檔案中的這些指示詞:

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

設定圖形對應屬性以控制裝飾項目的可視性

您可藉由在 DSL 定義中設定圖形與領域類別之間的對應,以控制裝飾項目的可視性,而不需要撰寫程式碼。 如需詳細資訊,請參閱如何定義特定領域語言

將圖形的色彩和樣式公開為屬性

在 DSL 定義中,以滑鼠右鍵按一下圖形類別,指向 [新增公開],然後按一下其中一個項目,例如 [填滿色彩]

圖形現在有一個領域屬性,您可以在程式碼中設定,或以使用者身分設定。 例如,若要在命令或規則的程式碼中設定該屬性,您可以撰寫:

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

如果您想讓屬性僅在程式控制之下可變,而不是由使用者控制,請在 DSL 定義圖中選取新的領域屬性,例如 [填滿色彩]。 然後,在 [屬性] 視窗中,將 Is Browsable 設定為 false,或將 Is UI Readonly 設為 true

定義變更規則,讓色彩、樣式或位置取決於模型元素屬性

您可定義規則,以根據模型的其他部分來更新圖形的外觀。 例如,您可以在模型元素上定義變更規則,以根據模型元素屬性來更新其圖形的色彩。 如需變更規則的詳細資訊,請參閱規則在模型內傳播變更

您應該只使用規則來更新 Store 內維護的屬性,因為執行復原命令時不會叫用規則。 這不包含一些圖形特性,例如圖形的大小和可視性。 若要更新圖形的這些特性,請參閱更新非 Store 圖形特性

下列範例假設您已將 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.
  }
}

這個方法可用於領域屬性和非 Store 特性,例如圖形的大小。

使用 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 是執行個體方法,但每個圖形類別只會叫用一次。