Partilhar via


Manipuladores de eventos propagam alterações fora do modelo

No SDK de Visualização e Modelagem, você pode definir manipuladores de eventos de repositório para propagar alterações para recursos fora do repositório, como variáveis e arquivos que não são do repositório, modelos em outros repositórios ou outras extensões do Visual Studio. Manipuladores de eventos de repositório são executados após o fim da transação na qual o evento de gatilho ocorreu. Eles também são executados em operações de Desfazer ou Refazer. Portanto, diferente das regras de repositório, os eventos de repositório são mais úteis para atualizar valores que estão fora do repositório. Diferente dos eventos do .NET, os manipuladores de eventos de repositório são registrados para escutar uma classe: você não precisa registrar um manipulador separado para cada instância. Para obter mais informações sobre como escolher entre diferentes maneiras de lidar com alterações, consulte Respondendo e propagando alterações.

A superfície gráfica e outros controles da interface do usuário são exemplos de recursos externos que podem ser manipulados por eventos do repositório.

Para definir um evento de repositório

  1. Escolha o tipo de evento que deseja monitorar. Para obter uma lista completa, examine as propriedades de EventManagerDirectory. Cada propriedade corresponde a um tipo de evento. Os tipos de evento usados com mais frequência são:

    • ElementAdded – disparado quando um elemento de modelo, link de relacionamento, forma ou conector é criado.

    • ElementPropertyChanged – disparado quando o valor de uma propriedade de domínio Normal é alterado. O evento será disparado somente se os valores novos e antigos não forem iguais. O evento não pode ser aplicado a propriedades de armazenamento calculadas e personalizadas.

      Ele não pode ser aplicado às propriedades de função que correspondem aos links de relação. Em vez disso, use ElementAdded para monitorar o relacionamento de domínio.

    • ElementDeleted – disparado após a exclusão de um elemento de modelo, relacionamento, forma ou conector. Você ainda pode acessar os valores de propriedade do elemento, mas ele não terá nenhuma relação com outros elementos.

  2. Adicione uma definição de classe parcial para YourDslDocData em um arquivo de código separado no projeto DslPackage.

  3. Escreva o código do evento como um método, como no exemplo a seguir. Pode ser static, a menos que você queira acessar DocData.

  4. Substitua OnDocumentLoaded() para registrar o manipulador. Se você tiver mais de um manipulador, poderá registrar todos eles no mesmo lugar.

O local do código de registro não é crítico. DocView.LoadView() é um local alternativo.

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

namespace Company.MusicLib
{
  partial class MusicLibDocData
  {
    // Register store events here or in DocView.LoadView().
    protected override void OnDocumentLoaded()
    {
      base.OnDocumentLoaded(); // Don't forget this.

      #region Store event handler registration.
      Store store = this.Store;
      EventManagerDirectory emd = store.EventManagerDirectory;
      DomainRelationshipInfo linkInfo = store.DomainDataDirectory
          .FindDomainRelationship(typeof(ArtistAppearsInAlbum));
      emd.ElementAdded.Add(linkInfo,
          new EventHandler<ElementAddedEventArgs>(AddLink));
      emd.ElementDeleted.Add(linkInfo,
          new EventHandler<ElementDeletedEventArgs>(RemoveLink));

      #endregion Store event handlers.
    }

    private void AddLink(object sender, ElementAddedEventArgs e)
    {
      ArtistAppearsInAlbum link = e.ModelElement as ArtistAppearsInAlbum;
      if (link != null)
            ExternalDatabase.Add(link.Artist.Name, link.Album.Title);
    }
    private void RemoveLink(object sender, ElementDeletedEventArgs e)
    {
      ArtistAppearsInAlbum link = e.ModelElement as ArtistAppearsInAlbum;
      if (link != null)
            ExternalDatabase.Delete(link.Artist.Name, link.Album.Title);
    }
  }
}

Usar eventos para fazer ajustes que não podem ser desfeitos no repositório

Normalmente, eventos de repositório não são usados para propagar alterações dentro do repositório, pois o manipulador de eventos é executado após a transação ser confirmada. Em vez disso, você usaria uma regra de repositório. Para obter mais informações, consulte Regras propagam alterações no modelo.

No entanto, você poderá usar um manipulador de eventos para fazer atualizações adicionais no repositório se quiser que o usuário possa desfazer atualizações adicionais separadamente do evento original. Por exemplo, digamos que caracteres em letras minúsculas sejam a convenção usual para títulos de álbum. Você pode escrever um manipulador de eventos de repositório que corrige o título para letras minúsculas após o usuário digitá-lo em letras maiúsculas. No entanto, o usuário pode usar o comando Desfazer para cancelar a correção, restaurando os caracteres em letras maiúsculas. Um segundo Desfazer removeria a alteração do usuário.

Por outro lado, se você escrevesse uma regra de repositório para fazer a mesma coisa, a alteração do usuário e a sua correção estariam na mesma transação, de modo que o usuário não poderia desfazer o ajuste sem perder a alteração original.

partial class MusicLibDocView
{
    // Register store events here or in DocData.OnDocumentLoaded().
    protected override void LoadView()
    {
      /* Register store event handler for Album Title property. */
      // Get reflection data for property:
      DomainPropertyInfo propertyInfo =
        this.DocData.Store.DomainDataDirectory
        .FindDomainProperty(Album.TitleDomainPropertyId);
      // Add to property handler list:
      this.DocData.Store.EventManagerDirectory
        .ElementPropertyChanged.Add(propertyInfo,
        new EventHandler<ElementPropertyChangedEventArgs>
             (AlbumTitleAdjuster));

      /*
      // Alternatively, you can set one handler for
      // all properties of a class.
      // Your handler has to determine which property changed.
      DomainClassInfo classInfo = this.Store.DomainDataDirectory
           .FindDomainClass(typeof(Album));
      this.Store.EventManagerDirectory
          .ElementPropertyChanged.Add(classInfo,
        new EventHandler<ElementPropertyChangedEventArgs>
             (AlbumTitleAdjuster));
       */
      return base.LoadView();
    }

// Undoable adjustment after a property is changed.
// Method can be static since no local access.
private static void AlbumTitleAdjuster(object sender,
         ElementPropertyChangedEventArgs e)
{
  Album album = e.ModelElement as Album;
  Store store = album.Store;

  // We mustn't update the store in an Undo:
  if (store.InUndoRedoOrRollback
      || store.InSerializationTransaction)
      return;

  if (e.DomainProperty.Id == Album.TitleDomainPropertyId)
  {
    string newValue = (string)e.NewValue;
    string lowerCase = newValue.ToLowerInvariant();
    if (!newValue.Equals(lowerCase))
    {
      using (Transaction t = store.TransactionManager
            .BeginTransaction("adjust album title"))
      {
        album.Title = lowerCase;
        t.Commit();
      } // Beware! This could trigger the event again.
    }
  }
  // else other properties of this class.
}

Se você escrever um evento que atualiza o repositório:

  • Use store.InUndoRedoOrRollback para evitar fazer alterações em elementos de modelo em Desfazer. O gerenciador de transação definirá tudo no repositório de volta para o estado original.

  • Use store.InSerializationTransaction para evitar fazer alterações enquanto o modelo está sendo carregado do arquivo.

  • As alterações farão com que outros eventos sejam disparados. Certifique-se de evitar um loop infinito.

Tipos de eventos de repositório

Cada tipo de evento corresponde a uma coleção em Store.EventManagerDirectory. Você pode adicionar ou remover manipuladores de eventos a qualquer momento, mas é comum adicioná-los quando o documento é carregado.

Nome da propriedade EventManagerDirectory Executado quando
ElementAdded Uma instância de uma classe de domínio, relacionamento de domínio, forma, conector ou diagrama é criada.
ElementDeleted Um elemento de modelo foi removido do diretório de elementos do repositório e não é mais a origem nem o destino de qualquer relacionamento. O elemento não é de fato excluído da memória, mas é mantido no caso de um Desfazer futuro.
ElementEventsBegun Invocado no final de uma transação externa.
ElementEventsEnded Invocado quando todos os outros eventos foram processados.
ElementMoved Um elemento de modelo foi movido de uma partição do repositório para outra.

Não está relacionado ao local de uma forma no diagrama.
ElementPropertyChanged O valor de uma propriedade de domínio foi alterado. Será executado somente se os valores antigos e novos forem diferentes.
RolePlayerChanged Uma das duas funções (extremidades) de um relacionamento faz referência a um novo elemento.
RolePlayerOrderChanged Em uma função com cardinalidade maior que 1, a sequência de links foi alterada.
TransactionBeginning
TransactionCommitted
TransactionRolledBack

Observação

O componente Transformação de Modelo de Texto é instalado automaticamente como parte da carga de trabalho de Desenvolvimento de extensões do Visual Studio. Você também pode instalá-lo na guia Componentes individuais do Instalador do Visual Studio, na categoria SDKs, bibliotecas e estruturas. Instale o componente SDK de Modelagem na guia Componentes individuais.