Compartir a través de


Los controladores de eventos propagan cambios fuera del modelo

En el SDK de visualización y modelado, puede definir controladores de eventos de almacén para propagar los cambios a los recursos fuera del almacén, como variables que no son de almacén, archivos, modelos en otros almacenes u otras extensiones de Visual Studio. Los controladores de eventos de almacenamiento se ejecutan después del final de la transacción en la que se produjo el evento desencadenador. También se ejecutan en una operación Deshacer o Rehacer. Por lo tanto, a diferencia de las reglas de tienda, los eventos de tienda son más útiles para actualizar los valores que están fuera de la tienda. A diferencia de los eventos de .NET, los controladores de eventos de almacén se registran para escuchar una clase: no es necesario registrar un controlador independiente para cada instancia. Para obtener más información sobre cómo elegir entre diferentes formas de controlar los cambios, vea Responder a los cambios y propagarlos.

La superficie gráfica y otros controles de interfaz de usuario son ejemplos de recursos externos que pueden ser manejados por eventos de la tienda.

Para definir un evento de almacén

  1. Elija el tipo de evento que desea supervisar. Para obtener una lista completa, examine las propiedades de EventManagerDirectory. Cada propiedad corresponde a un tipo de evento. Los tipos de eventos más usados son:

    • ElementAdded : se desencadena cuando se crea un elemento de modelo, un vínculo de relación, una forma o un conector.

    • ElementPropertyChanged: se desencadena cuando se cambia el valor de una Normal propiedad de dominio. El evento solo se desencadena si los valores nuevos y antiguos no son iguales. El evento no se puede aplicar a las propiedades de almacenamiento calculadas y personalizadas.

      No se puede aplicar a las propiedades de rol que corresponden a vínculos de relación. En su lugar, use ElementAdded para supervisar la relación de dominio.

    • ElementDeleted : se desencadena después de eliminar un elemento de modelo, una relación, una forma o un conector. Todavía puede tener acceso a los valores de propiedad del elemento, pero no tendrá relaciones con otros elementos.

  2. Agregue una definición de clase parcial para YourDslDocData en un archivo de código independiente en el proyecto DslPackage .

  3. Escriba el código del evento como un método, como en el ejemplo siguiente. Puede ser static, a menos que desee acceder a DocData.

  4. Sobrescriba OnDocumentLoaded() para registrar el controlador. Si tiene más de un controlador, puede registrarlos todos en el mismo lugar.

La ubicación del código de registro no es fundamental. DocView.LoadView() es una ubicación alternativa.

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 realizar ajustes reversibles en la Tienda

Normalmente, los eventos del almacén de datos no se utilizan para propagar cambios dentro del mismo, ya que el manejador de eventos se ejecuta después de que se haya confirmado la transacción. En su lugar, usarías una regla de tienda. Para obtener más información, consulte Reglas de propagación de cambios dentro del modelo.

Sin embargo, podría usar un controlador de eventos para realizar actualizaciones adicionales en el almacén, si desea que el usuario pueda deshacer las actualizaciones adicionales por separado del evento original. Por ejemplo, supongamos que los caracteres en minúsculas son la convención habitual para los títulos del álbum. Puede escribir un controlador de eventos de almacén que corrija el título en minúsculas después de que el usuario lo haya escrito en mayúsculas. Pero el usuario podría usar el comando Deshacer para cancelar la corrección, restaurando los caracteres mayúsculas. Un segundo Deshacer quitaría el cambio del usuario.

Por el contrario, si escribió una regla de tienda para hacer lo mismo, el cambio del usuario y la corrección estarían en la misma transacción, de modo que el usuario no pudiera deshacer el ajuste sin perder el cambio 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.
}

Si escribe un evento que actualiza la tienda:

  • Use store.InUndoRedoOrRollback para evitar realizar cambios en los elementos del modelo en Deshacer. El administrador de transacciones establecerá todo en el almacén en su estado original.

  • Use store.InSerializationTransaction para evitar realizar cambios mientras se carga el modelo desde el archivo.

  • Los cambios harán que se desencadenen más eventos. Asegúrese de evitar un bucle infinito.

Almacenar tipos de eventos

Cada tipo de evento corresponde a una colección de Store.EventManagerDirectory. Puede agregar o quitar controladores de eventos en cualquier momento, pero es habitual agregarlos cuando se carga el documento.

EventManagerDirectory Nombre de propiedad Se ejecuta cuando
ElementAdded Se crea una instancia de una clase de dominio, una relación de dominio, una forma, un conector o un diagrama.
Elemento Eliminado Se ha eliminado un elemento de modelo del directorio de elementos de la tienda y ya no es el origen ni el destino de ninguna relación. El elemento no se elimina realmente de la memoria, sino que se conserva en caso de una futura acción de deshacer.
ElementEventsBegun Se invoca al final de una transacción externa.
ElementEventsEnded Se invoca cuando se han procesado todos los demás eventos.
ElementMoved Un elemento de modelo se ha movido de una partición de almacén a otra.

Esto no está relacionado con la ubicación de una forma en el diagrama.
CambioDePropiedadDelElemento El valor de una propiedad de dominio ha cambiado. Esto solo se ejecuta si los valores antiguos y nuevos no son iguales.
RolePlayerChanged Uno de los dos roles (extremos) de una relación hace referencia a un nuevo elemento.
OrdenDeJugadoresCambiada En un rol con multiplicidad mayor que 1, la secuencia de vínculos ha cambiado.
InicioDeTransacción
Transacción Confirmada
TransacciónRevertida

Nota:

El componente Transformación de Plantillas de Texto se instala automáticamente como parte de la tarea Desarrollo de Extensiones de Visual Studio. También puede instalarlo desde la pestaña Componentes individuales del Instalador de Visual Studio, en la categoría SDK, bibliotecas y marcos . Instale el componente SDK de modelado desde la pestaña Componentes individuales .