Atualizar formas e conectores para refletir o modelo

Em uma linguagem específica de domínio no Visual Studio, você pode fazer com que a aparência de uma forma reflita o estado do modelo subjacente.

Os exemplos de código neste tópico devem ser adicionados a um arquivo .cs em seu projeto Dsl. Você precisa destas diretivas em cada arquivo:

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

Definir propriedades do Mapa da Formas para controlar a visibilidade de um decorador

Você pode controlar a visibilidade de um decorador sem escrever código do programa, configurando o mapeamento entre a forma e a classe de domínio na Definição de DSL. Para obter mais informações, confira Como definir uma Linguagem Específica de Domínio.

Expor a cor e o estilo de uma forma como propriedades

Na Definição de DSL, clique com o botão direito do mouse na classe de forma, aponte para Adicionar Exposto e clique em um dos itens, como Cor de Preenchimento.

A forma agora tem uma propriedade de domínio que você pode definir no código do programa ou como um usuário. Por exemplo, para defini-la no código do programa de um comando ou regra, você pode escrever:

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

Se você quiser tornar propriedade variável somente sob controle do programa, e não do usuário, selecione a nova propriedade de domínio, como Cor de Preenchimento, no diagrama de Definição de DSL. Em seguida, no janela Propriedades, defina É navegável como false ou defina É somente leitura na interface do usuário como true.

Definir Regras de Alteração para tornar a cor, o estilo ou o local dependentes das propriedades do elemento de modelo

Você pode definir regras que atualizam a aparência da forma de modo dependente de outras partes do modelo. Por exemplo, você pode definir uma Regra de Alteração em um elemento de modelo que atualiza a cor de sua forma de modo dependente das propriedades do elemento modelo. Para obter mais informações sobre as Regras de Alteração, consulte Regras propagam alterações no modelo.

Use as regras apenas para atualizar as propriedades mantidas no repositório, pois as regras não são invocadas quando o comando Desfazer é executado. Isso não inclui alguns recursos gráficos, como o tamanho e a visibilidade de uma forma. Para atualizar esses recursos de uma forma, consulte Atualizando recursos gráficos que não são do repositório.

O exemplo a seguir pressupõe que você tenha exposto FillColor como uma propriedade de domínio, conforme descrito na seção anterior.

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

Usar OnChildConfigured para inicializar as propriedades de uma forma

Para definir as propriedades de uma forma quando ela é criada pela primeira vez, substitua OnChildConfigured() em uma definição parcial da classe de diagrama. A classe de diagrama é especificada na Definição de DSL e o código gerado está em Dsl\Generated Code\Diagram.cs. Por exemplo:

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

Esse método pode ser usado tanto para propriedades de domínio quanto para recursos que não são do repositório, como o tamanho da forma.

Usar AssociateValueWith() para atualizar outros recursos de uma forma

Para alguns recursos de uma forma, por exemplo, se ela tem uma sombra ou o estilo de seta de um conector, não há nenhum método interno para expor o recurso como uma propriedade de domínio. Alterações nesses recursos não estão sob controle do sistema de transações. Portanto, não é apropriado atualizá-los usando regras, pois as regras não são invocadas quando o usuário executa o comando Desfazer.

Em vez disso, você pode atualizar esses recursos usando OnAssociatedPropertyChanged. No exemplo a seguir, o estilo da seta de um conector é controlado por um valor de uma propriedade de domínio na relação que o conector exibe:

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() deve ser chamado uma vez para cada propriedade de domínio que você deseja registrar. Após ele ser chamado, qualquer alteração na propriedade especificada chamará OnAssociatedPropertyChanged() em todas as formas que apresentarem o elemento de modelo da propriedade.

Não é necessário chamar AssociateValueWith() para cada instância. Embora InitializeResources seja um método de instância, ele é invocado apenas uma vez para cada classe de forma.