Compartilhar via


Regras propagam alterações dentro do modelo

Você pode criar uma regra de repositório para propagar uma alteração de um elemento para outro no SDK de Visualização e Modelagem (VMSDK). Quando ocorre uma alteração em qualquer elemento na Loja, as regras são agendadas para serem executadas, geralmente quando a transação mais externa é confirmada. Há diferentes tipos de regras para diferentes tipos de eventos, como adicionar um elemento ou excluí-lo. Você pode anexar regras a tipos específicos de elementos, formas ou diagramas. Muitos recursos internos são definidos por regras: por exemplo, as regras garantem que um diagrama seja atualizado quando o modelo for alterado. Você pode personalizar seu idioma específico do domínio adicionando suas próprias regras.

As regras de repositório são particularmente úteis para propagar alterações dentro do repositório, ou seja, alterações em elementos de modelo, relações, formas ou conectores e suas propriedades de domínio. As regras não são executadas quando o usuário invoca os comandos Desfazer ou Refazer. Em vez disso, o gerenciador de transações garante que o conteúdo do repositório seja restaurado para o estado correto. Se você quiser propagar alterações em recursos fora do repositório, use Eventos da Loja. Para obter mais informações, consulte Manipuladores de Eventos Propagam Alterações Fora do Modelo.

Por exemplo, suponha que você queira 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ê pode escrever um AddRule e associá-lo ao ExampleDomainClass. Você escreveria 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ção

O código de uma regra deve alterar o estado apenas dos elementos dentro do Repositório; ou seja, a regra deve alterar apenas elementos de modelo, relações, formas, conectores, diagramas ou suas propriedades. Se você quiser propagar alterações em recursos fora do repositório, defina Eventos do Repositório. Para obter mais informações, consulte Manipuladores de Eventos Propagam Alterações Fora do Modelo.

Para definir uma regra

  1. Defina a regra como uma classe prefixada com o RuleOn atributo. O atributo associa a regra a uma de suas classes de domínio, relações ou elementos de diagrama. A regra será aplicada a todas as instâncias dessa classe, o que pode ser abstrato.

  2. Registre a regra adicionando-a ao conjunto retornado pela classe de modelo de domínio GetCustomDomainModelTypes().

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

    As secções seguintes descrevem estes passos mais detalhadamente.

Para definir uma regra em uma classe de domínio

  • Em um arquivo de código personalizado, defina uma classe e prefixe-a 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 assunto no primeiro parâmetro pode ser uma classe de domínio, relação de domínio, forma, conector ou diagrama. Normalmente, você aplica regras a classes de domínio e relações.

    O FireTime é geralmente TopLevelCommit. Isso garante que a regra seja executada somente após todas as alterações primárias da transação terem sido feitas. As alternativas são Inline, que executa a regra logo após a alteração; e LocalCommit, que executa a regra no final da transação atual (a qual pode não ser a mais externa). Você também pode definir a prioridade de uma regra para afetar sua ordenação na fila, mas esse é um método não confiável para alcançar o resultado necessário.

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

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

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

Para registrar a regra

  • Adicione sua classe de regra à lista de tipos retornados pelo GetCustomDomainModelTypes 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 classe de modelo de domínio, examine dentro do arquivo Dsl\GeneratedCode\DomainModel.cs

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

Para escrever o código da regra

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

    Classe base Trigger
    AddRule Um elemento, um link ou uma forma é adicionado.

    Use isso para detectar novas relações, além de novos elementos.
    ChangeRule Um valor de propriedade de domínio é alterado. O argumento do método fornece os valores antigos e novos.

    Para formas, essa regra é disparada quando a propriedade interna AbsoluteBounds é alterada, se a forma é movida.

    Em muitos casos, é mais conveniente substituir OnValueChanged ou OnValueChanging no manipulador de propriedades. Esses métodos são chamados imediatamente antes e depois da alteração. Por outro lado, a regra geralmente é executada no final da transação. Para obter mais informações, consulte Manipuladores de alteração de valor da propriedade de domínio. Nota: Essa regra não é disparada quando um link é criado ou excluído. Em vez disso, escreva um AddRule e um DeleteRule para a relação de domínio.
    DeletingRule Disparado quando um elemento ou link vai ser excluído. A propriedade ModelElement.IsDeleting é verdadeira até o final da transação.
    DeleteRule Executado quando um elemento ou link foi excluído. A regra é executada depois que todas as outras regras foram executadas, incluindo DeletingRules. ModelElement.IsDeleting é false e ModelElement.IsDeleted é true. Para permitir um desfazer posterior, o elemento não é realmente removido da memória, mas é removido de Store.ElementDirectory.
    MoveRule Um elemento é movido de uma partição de repositório para outra.

    (Observe que isso não está relacionado à posição gráfica de uma forma.)
    RolePlayerChangeRule Essa regra se aplica somente a relações de domínio. Ele será disparado se você atribuir explicitamente um elemento de modelo a uma das extremidades de um link.
    RolePlayerPositionChangeRule Disparado quando a ordenação de links de ou para 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 tem um método que você substitui. Digite override em sua classe para descobri-lo. 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 mais externa é 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 precisa criar uma nova transação para fazer alterações.

  3. As regras não são executadas quando uma transação é revertida ou quando as operações Desfazer ou Refazer são executadas. Essas operações redefinem todo o conteúdo da Loja para seu estado anterior. Portanto, se a regra alterar o estado de qualquer coisa fora da Loja, ela poderá não manter a sincronização com o conteúdo da Loja. Para atualizar o estado fora da Loja, é 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 o carregamento ou salvamento está em andamento, use store.TransactionManager.CurrentTransaction.IsSerializing.

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

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

  7. Use regras depois de considerar outras alternativas. Por exemplo, se você quiser atualizar uma propriedade quando um valor for alterado, considere usar uma propriedade calculada. Se você quiser restringir o tamanho ou o local de uma forma, use um BoundsRule. Se você quiser responder a uma alteração em um valor de propriedade, adicione um OnValueChanged manipulador à propriedade. Para mais informações, consulte Responder e Propagar Alterações.

Example

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

Para testar este exemplo, crie uma DSL usando o modelo de solução fluxo de tarefas e insira o código a seguir em um arquivo no projeto DsL. Crie e execute a solução e abra o arquivo de exemplo no projeto de depuração. Desenhe um Link de Comentário entre uma forma de comentário e um elemento de fluxo. O texto no comentário é alterado para relatar o elemento mais recente ao qual você o conectou.

Na prática, você normalmente escreveria um 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();
    }
  }

}