更新圖形和接點來反映模型
在 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 是執行個體方法,但每個圖形類別只會叫用一次。