Partilhar via


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

Dica

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ções nos valores de propriedades de domínio.

    Dica

    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 alterações e propagando-as.

    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 restringem o local e o tamanho de uma forma