Compartilhar via


Regras de propagam alterações dentro do modelo

Você pode criar uma regra de armazenamento para propagar uma alteração de um elemento para outro na visualização e modelagem SDK (VMSDK).Quando ocorre uma alteração a qualquer elemento no armazenamento, as regras estão programadas para ser executado, geralmente quando a transação externa for confirmada.Existem diferentes tipos de regras para diferentes tipos de eventos, como, por exemplo, adicionando um elemento ou excluí-lo.Você pode anexar regras a tipos específicos de elementos, formas ou diagramas.Muitos recursos internos são definidos pelas regras: por exemplo, regras garantem que um diagrama é atualizado quando o modelo é alterado.Você pode personalizar sua linguagem específica de domínio adicionando suas próprias regras.

Regras de armazenamento são particularmente úteis para propagar as alterações dentro do armazenamento – ou seja, altera para elementos de modelo, relacionamentos, formas ou conectores e seu domínio de propriedades.As regras não são executados quando o usuário aciona os comandos Desfazer ou refazer.Em vez disso, o Gerenciador de transações certifica-se de que o conteúdo do armazenamento é restaurado ao estado correto.Se você deseja propagar alterações para recursos fora do armazenamento, use a armazenar eventos.Para obter mais informações, consulte Manipuladores de eventos propagam alterações fora do modelo.

Por exemplo, suponha que você deseja especificar que, sempre que o usuário (ou seu código) cria um novo elemento do tipo ExampleDomainClass, um elemento adicional de outro tipo é criado em outra parte do modelo.Você poderia escrever um AddRule e associá-lo a ExampleDomainClass.Você poderia escrever o código na regra para criar o elemento adicional.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.Modeling;

namespace ExampleNamespace
{
 // Attribute associates the rule with a domain class:
 [RuleOn(typeof(ExampleDomainClass), FireTime=TimeToFire.TopLevelCommit)]
 // The rule is a class derived from one of the abstract rules:
 class MyAddRule : AddRule
 {
  // Override the abstract method:
  public override void ElementAdded(ElementAddedEventArgs e)
  {
    base.ElementAdded(e);
    ExampleDomainClass element = e.ModelElement;
    Store store = element.Store;
    // Ignore this call if we're currently loading a model:
    if (store.TransactionManager.CurrentTransaction.IsSerializing) 
       return;
    
    // Code here propagates change as required – for example:
      AnotherDomainClass echo = new AnotherDomainClass(element.Partition);
      echo.Name = element.Name;
      echo.Parent = element.Parent;  
    }
  }
 // The rule must be registered:
 public partial class ExampleDomainModel
 {
   protected override Type[] GetCustomDomainModelTypes()
   {
     List<Type> types = new List<Type>(base.GetCustomDomainModelTypes());
     types.Add(typeof(MyAddRule));
     // If you add more rules, list them here. 
     return types.ToArray();
   }
 }
}
ObservaçãoObservação

O código de uma regra deve alterar o estado somente de elementos dentro do armazenamento; ou seja, a regra deve alterar apenas os elementos de modelo, relacionamentos, formas, conectores, diagramas ou suas propriedades.Se você deseja propagar alterações para recursos fora do armazenamento, defina a armazenar eventos.Para mais informações, consulte: Manipuladores de eventos propagam alterações fora do modelo.

Para definir uma regra

  1. Definir a regra como uma classe prefixado com o RuleOn atributo.O atributo associa a regra de uma de suas classes de domínio, relacionamentos ou elementos de diagrama.A regra será aplicada a cada instância dessa classe, que pode ser abstrato.

  2. Registre-se a regra de disponibilizá-lo para o conjunto retornado por GetCustomDomainModelTypes() na sua classe de modelo de domínio.

  3. Derivar a classe de regra de uma dentre as classes abstratas de regra e escrever o código do método de execução.

As seções a seguir descrevem essas etapas mais detalhadamente.

Para definir uma regra em uma classe de domínio

  • Em um arquivo de código personalizado, definir uma classe e um prefixo com o RuleOnAttribute atributo:

    [RuleOn(typeof(ExampleElement), 
         // Usual value – but required, because it is not the default:
         FireTime = TimeToFire.TopLevelCommit)] 
    class MyRule ...
    
  • O tipo de entidade no primeiro parâmetro pode ser uma classe de domínio, a relação de domínio, a forma, a conector ou o diagrama.Normalmente, você aplica regras às relações e classes de domínio.

    The FireTime is usually TopLevelCommit.Isso garante que a regra é executada somente após todas as principais alterações da transação foram feitas.As alternativas são embutidas, que será executada a regra logo após a alteração; e LocalCommit, que executa a regra no final da transação atual (que pode não ser o mais externo).Você também pode definir a prioridade de uma regra para afetar seus pedidos na fila, mas este é um método confiável de atingir o resultado que necessário.

  • Você pode especificar uma classe abstrata como o tipo de entidade.

  • A regra se aplica a todas as instâncias da classe de entidade.

  • O valor padrão para FireTime é TimeToFire.TopLevelCommit.Isso faz com que a regra a ser executado quando a transação externa for confirmada.Uma alternativa é TimeToFire.Inline.Isso faz com que a regra a ser executada logo após o evento de disparo.

Para registrar a regra

  • Adiciona a sua classe de regra à lista de tipos retornados por GetCustomDomainModelTypes no seu modelo de domínio:

    public partial class ExampleDomainModel
     {
       protected override Type[] GetCustomDomainModelTypes()
       {
         List<Type> types = new List<Type>(base.GetCustomDomainModelTypes());
         types.Add(typeof(MyAddRule));
         // If you add more rules, list them here. 
         return types.ToArray();
       }
     }
    
  • Se você não tiver certeza do nome da sua classe de modelo de domínio, olhe dentro do arquivo.Dsl\GeneratedCode\DomainModel.cs

  • Escreva esse código em um arquivo de código personalizado em seu projeto DSL.

Escrever o código da regra

  • Derive a classe de regra de uma das seguintes classes base:

    Classe base

    Disparador

    AddRule

    É adicionada a um elemento, link ou forma.

    Use esta opção para detectar novas relações, com novos elementos.

    ChangeRule

    Um valor de propriedade de domínio é alterado.O argumento do método fornece os valores novos e antigos.

    Para formas, esta regra for acionada quando interno AbsoluteBounds alterações de propriedade, se a forma é movida.

    Em muitos casos, é mais conveniente substituir OnValueChanged ou OnValueChanging no manipulador de propriedade.Esses métodos são chamados imediatamente antes e depois da alteração.Por outro lado, a regra é executada normalmente no final da transação.Para obter mais informações, consulte Manipuladores de alteração de valor de propriedade de domínio.

    ObservaçãoObservação
    Esta regra não é disparada quando um link é criado ou excluído.Em vez disso, escrever um AddRule e um DeleteRule para a relação de domínio.

    DeletingRule

    Acionado quando um elemento ou link está prestes a ser excluído.A propriedade ModelElement.IsDeleting é verdadeira até o final da transação.

    DeleteRule

    Executada quando um elemento ou link foi excluído.A regra é executada depois que todas as outras regras tiverem sido executadas, incluindo o DeletingRules.ModelElement.IsDeleting é falso e ModelElement.IsDeleted é verdadeiro.Para permitir um desfazer subseqüente, o elemento não é efetivamente removido da memória, mas ele é removido do Store.ElementDirectory.

    MoveRule

    Um elemento é movido de um armazenamento partição para outra.

    (Observe que isso não está relacionado à posição de uma forma gráfica).

    RolePlayerChangeRule

    Essa regra se aplica apenas às relações entre domínios.Se você atribuir explicitamente um elemento de modelo para uma das extremidades de um link é disparado.

    RolePlayerPositionChangeRule

    Acionado quando a ordem dos links para ou de um elemento é alterada usando os métodos MoveBefore ou MoveToIndex em um link.

    TransactionBeginningRule

    Executado quando uma transação é criada.

    TransactionCommittingRule

    Executado quando a transação está prestes a ser confirmada.

    TransactionRollingBackRule

    Executado quando a transação está prestes a ser revertida.

  • Cada classe possui um método que você substituir.Tipo de override na sua classe detecte.O parâmetro desse método identifica o elemento que está sendo alterado.

Observe os seguintes pontos sobre regras:

  1. O conjunto de alterações em uma transação pode disparar muitas regras.Normalmente, as regras são executadas quando a transação externa for confirmada.Eles são executados em uma ordem não especificada.

  2. Uma regra é sempre executada dentro de uma transação.Portanto, você não precisará criar uma nova transação para fazer alterações.

  3. Regras não serão executadas quando uma transação é revertida, ou quando as operações de desfazer ou refazer serão realizadas.Essas operações redefinir todo o conteúdo do armazenamento ao seu estado anterior.Portanto, se sua regra altera o estado de qualquer coisa fora do armazenamento, ele talvez não tenha em synchronism com o armazenamento de conteúdo.Para atualizar o estado fora do armazenamento, é melhor usar eventos.Para obter mais informações, consulte Manipuladores de eventos propagam alterações fora do modelo.

  4. Algumas regras são executadas quando um modelo é carregado do arquivo.Para determinar se carregando ou salvando está em andamento, use store.TransactionManager.CurrentTransaction.IsSerializing.

  5. Se o código da sua regra cria mais disparadores de regra, eles serão adicionados ao final da lista de acionamento e serão executados antes de concluída a transação.DeletedRules são executados após todas as outras regras.Uma regra pode executar muitas vezes em uma transação, uma vez para cada alteração.

  6. Para passar informações para e de regras, você pode armazenar informações no TransactionContext.Este é apenas um dicionário que será mantido durante a transação.Ele é descartado quando a transação termina.Os argumentos do evento em cada regra fornecem acesso a ele.Lembre-se de que as regras não são executadas em uma ordem previsível.

  7. Usar regras após considerar outras alternativas.Por exemplo, se você quiser atualizar uma propriedade quando um valor é alterado, considere o uso de uma propriedade calculada.Se você deseja restringir o tamanho ou a localização de uma forma, use um BoundsRule.Se você quiser responder a uma alteração no valor de uma propriedade, adicione um OnValueChanged manipulador para a propriedade.Para obter mais informações, consulte Respondendo a e propagação de alterações.

Exemplo

O exemplo a seguir atualiza uma propriedade quando uma relação de domínio é instanciada para vincular os dois elementos.A regra será acionada não apenas quando o usuário cria um link em um diagrama, mas também se o código de programa cria um vínculo.

Para testar este exemplo, crie uma DSL usando o modelo de fluxo de tarefas de solução e insira o código a seguir em um arquivo no projeto Dsl.Construir e executar a solução e abrir o arquivo de exemplo no projeto Debugging.Desenhe um Link de comentário entre uma forma de comentário e um elemento de fluxo.O texto no comentário muda para informar sobre o elemento mais recente que você conectou a ele.

Na prática, você geralmente escreveria uma DeleteRule para cada AddRule.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.Modeling;

namespace Company.TaskRuleExample
{

  [RuleOn(typeof(CommentReferencesSubjects))]
  public class RoleRule : AddRule
  {

    public override void ElementAdded(ElementAddedEventArgs e)
    {
      base.ElementAdded(e);
      CommentReferencesSubjects link = e.ModelElement as CommentReferencesSubjects;
      Comment comment = link.Comment;
      FlowElement subject = link.Subject;
      Transaction current = link.Store.TransactionManager.CurrentTransaction;
      // Don't want to run when we're just loading from file:
      if (current.IsSerializing) return;
      comment.Text = "Flow has " + subject.FlowTo.Count + " outgoing connections";
    }
    
  }

  public partial class TaskRuleExampleDomainModel
  {
    protected override Type[] GetCustomDomainModelTypes()
    {
      List<Type> types = new List<Type>(base.GetCustomDomainModelTypes());
      types.Add(typeof(RoleRule));
      return types.ToArray();
    }
  }

}

Consulte também

Conceitos

Manipuladores de eventos propagam alterações fora do modelo

BoundsRules restringir o tamanho e a localização de forma