Поделиться через


Обработчики событий распространяют изменения за пределы модели

В пакете SDK для визуализации и моделирования можно определить обработчики событий хранилища для распространения изменений на ресурсы за пределами хранилища, такие как переменные, файлы, модели в других хранилищах или другие расширения Visual Studio. Обработчики событий магазина выполняются после окончания транзакции, в которой произошло событие активации. Они также выполняются в операции отмены или повторного выполнения. Поэтому, в отличие от правил хранения, события хранения наиболее полезны для обновления значений, которые находятся за пределами хранилища. В отличие от событий .NET, обработчики событий магазина регистрируются для прослушивания класса: для каждого экземпляра не требуется регистрировать отдельный обработчик. Дополнительные сведения о том, как выбрать различные способы обработки изменений, см. в статье "Ответы на изменения" и "Распространение изменений".

Графические поверхности и другие элементы управления пользовательским интерфейсом являются примерами внешних ресурсов, которые могут обрабатываться событиями хранилища.

Определение события хранилища

  1. Выберите тип события, которое требуется отслеживать. Полный список см. в описании EventManagerDirectoryсвойств . Каждое свойство соответствует типу события. Наиболее часто используемые типы событий:

    • ElementAdded — активируется при создании элемента модели, связи, фигуры или соединителя.

    • ElementPropertyChanged — активируется при изменении значения Normal свойства домена. Событие активируется только в том случае, если новые и старые значения не равны. Событие нельзя применить к вычисляемым и пользовательским свойствам хранилища.

      Его нельзя применить к свойствам роли, соответствующим ссылкам связи. Вместо этого используйте ElementAdded для мониторинга связи домена.

    • ElementDeleted — активируется после удаления элемента модели, связи, фигуры или соединителя. Вы по-прежнему можете получить доступ к значениям свойств элемента, но у него нет связей с другими элементами.

  2. Добавьте определение частичного класса для DocData YourDslв отдельный файл кода в проекте DslPackage.

  3. Напишите код события в качестве метода, как показано в следующем примере. Это может быть static, если вы не хотите получить доступ DocData.

  4. Переопределите OnDocumentLoaded() для регистрации обработчика. Если у вас несколько обработчиков, их можно зарегистрировать в одном месте.

Расположение кода регистрации не является критическим. DocView.LoadView() — это альтернативное расположение.

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

Использование событий для отмены изменений в Магазине

События хранилища обычно не используются для распространения изменений внутри хранилища, так как обработчик событий выполняется после фиксации транзакции. Вместо этого вы будете использовать правило хранилища. Дополнительные сведения см. в разделе "Правила распространения изменений в модели".

Однако можно использовать обработчик событий для внесения дополнительных обновлений в хранилище, если пользователь сможет отменить дополнительные обновления отдельно от исходного события. Например, предположим, что символы нижнего регистра являются обычным соглашением для названий альбомов. Вы можете написать обработчик событий магазина, который исправляет заголовок на нижний регистр после того, как пользователь ввел его в верхнем регистре. Но пользователь может использовать команду отмены для отмены исправления, восстанавливая символы верхнего регистра. Вторая отмена приведет к удалению изменения пользователя.

В отличие от этого, если вы написали правило хранилища, чтобы сделать то же самое, изменение пользователя и исправление будет находиться в той же транзакции, чтобы пользователь не мог отменить корректировку без потери исходного изменения.

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.
}

Если вы напишете событие, которое обновляет хранилище:

  • Используйте store.InUndoRedoOrRollback для предотвращения внесения изменений в элементы модели в undo. Диспетчер транзакций установит все в хранилище обратно в исходное состояние.

  • Используйте store.InSerializationTransaction для предотвращения внесения изменений во время загрузки модели из файла.

  • Изменения будут вызваны дальнейшими событиями. Убедитесь, что вы избегаете бесконечного цикла.

Типы событий Store

Каждый тип события соответствует коллекции в Store.EventManagerDirectory. Обработчики событий можно добавлять или удалять в любое время, но обычно добавлять их при загрузке документа.

EventManagerDirectory Имя свойства Выполняется при выполнении
ЭлементAdded Создается экземпляр класса домена, отношения домена, фигуры, соединителя или схемы.
ЭлементDeleted Элемент модели был удален из каталога элементов хранилища и больше не является источником или целевым объектом любой связи. Элемент не удаляется из памяти, но сохраняется в случае будущего отмены.
ElementEventsBegun Вызывается в конце внешней транзакции.
ElementEventsEnded Вызывается при обработке всех других событий.
ElementMoved Элемент модели был перемещен из одной секции хранилища в другую.

Это не связано с расположением фигуры на схеме.
ElementPropertyChanged Значение свойства домена изменилось. Это выполняется только в том случае, если старые и новые значения не равны.
RolePlayerChanged Одна из двух ролей (заканчивается) связи ссылается на новый элемент.
RolePlayerOrderChanged В роли с кратностью больше 1 последовательность ссылок изменилась.
TransactionBeginning
TransactionCommitted
TransactionRolledBack

Примечание.

Компонент Text Template Transformation (Преобразование текстовых шаблонов) автоматически устанавливается как часть рабочей нагрузки разработки расширений Visual Studio. Его также можно установить на вкладке Отдельные компоненты Visual Studio Installer в категории Пакеты SDK, библиотеки и платформы. Установите компонент Пакет SDK для моделирования со вкладки Отдельные компоненты.