Mettre à jour les formes et les connecteurs pour refléter le modèle

Dans un langage spécifique à un domaine dans Visual Studio, vous pouvez faire en sorte que l’apparence d’une forme reflète l’état du modèle sous-jacent.

Les exemples de code de cette rubrique doivent être ajoutés à un fichier .cs dans votre projet Dsl. Vous avez besoin de ces directives dans chaque fichier :

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

Définir les propriétés du mappage de formes pour contrôler la visibilité d’un décorateur

Vous pouvez contrôler la visibilité d’un décorateur sans écrire de code de programme en configurant le mappage entre la forme et la classe de domaine dans la définition DSL. Pour plus d’informations, consultez Comment définir un langage spécifique à un domaine.

Exposer la couleur et le style d’une forme en tant que propriétés

Dans la définition DSL, faites un clic droit sur la classe de forme, pointez sur Ajouter un exposé, puis cliquez sur l’un des éléments tels que Couleur de remplissage.

La forme possède désormais une propriété de domaine que vous pouvez définir dans le code du programme ou en tant qu’utilisateur. Par exemple, pour le définir dans le code de programme d’une commande ou d’une règle, vous pouvez écrire :

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

Si vous souhaitez rendre la variable de propriété uniquement sous contrôle du programme, et non de l’utilisateur, sélectionnez la nouvelle propriété de domaine telle que la Couleur de remplissage dans le diagramme de définition DSL. Ensuite, dans la fenêtre Propriétés, définissez Is Browsable sur false ou définissez Is UI Readonly sur true.

Définir des règles de modification pour que la couleur, le style ou l’emplacement dépendent des propriétés des éléments de modèle

Vous pouvez définir des règles qui mettent à jour l’apparence de la forme en fonction d’autres parties du modèle. Par exemple, vous pouvez définir une règle de modification sur un élément de modèle qui met à jour la couleur de sa forme en fonction des propriétés de l’élément de modèle. Pour plus d’informations sur les règles de modification, consultez Propagation de modifications dans le modèle par des règles.

Vous devez utiliser des règles uniquement pour mettre à jour les propriétés conservées dans le Store, car les règles ne sont pas appelées lorsque la commande Annuler est effectuée. Cela n’inclut pas certaines fonctionnalités graphiques telles que la taille et la visibilité d’une forme. Pour mettre à jour ces fonctionnalités d’une forme, consultez Mise à jour des fonctionnalités graphiques hors magasin.

L’exemple suivant suppose que vous avez exposé FillColor en tant que propriété de domaine comme décrit dans la section précédente.

[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();
    }
  }

Utiliser OnChildConfigured pour initialiser les propriétés d’une forme

Pour définir les propriétés d’une forme lors de sa première création, remplacez OnChildConfigured() dans une définition partielle de votre classe de diagramme. La classe de diagramme est spécifiée dans votre définition DSL et le code généré se trouve dans Dsl\Generated Code\Diagram.cs. Par exemple :

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.
  }
}

Cette méthode peut être utilisée à la fois pour les propriétés de domaine et les fonctionnalités hors magasin, telles que la taille de la forme.

Utiliser AssociateValueWith() pour mettre à jour d’autres fonctionnalités d’une forme

Pour certaines caractéristiques d’une forme, comme la présence d’une ombre ou le style de flèche d’un connecteur, il n’existe aucune méthode intégrée d’exposition de la fonctionnalité en tant que propriété de domaine. Les modifications apportées à ces fonctionnalités ne sont pas sous le contrôle du système de transaction. Par conséquent, il n’est pas approprié de les mettre à jour à l’aide de règles, car les règles ne sont pas appelées lorsque l’utilisateur exécute la commande Annuler.

Au lieu de cela, vous pouvez mettre à jour ces fonctionnalités à l’aide de OnAssociatedPropertyChanged. Dans l’exemple suivant, le style de flèche d’un connecteur est contrôlé par une valeur d’une propriété de domaine dans la relation que le connecteur affiche :

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() doit être appelé une fois pour chaque propriété de domaine que vous souhaitez inscrire. Une fois qu’elle a été appelée, toutes les modifications apportées à la propriété spécifiée appelleront OnAssociatedPropertyChanged() pour les formes qui présentent l’élément de modèle de la propriété.

Il n’est pas nécessaire d’appeler AssociateValueWith() pour chaque instance. Bien que InitializeResources soit une méthode d’instance, elle n’est appelée qu’une seule fois pour chaque classe de forme.