事件处理程序在模型外部传播更改

在可视化和建模 SDK,则可以定义存储事件处理程序会传播到资源的更改在存储外,例如非存储变量、文件、设计在其他存储中,或其他 Visual Studio 扩展。 存储事件处理程序在该触发的事件发生事务后的结尾时执行。 它们在撤消也会执行或重做操作。 因此,与存储规则,存储事件为更新是在存储外的值是最为有用。 不同于 .NET 事件,存储事件处理程序已注册为侦听类:您不必注册每个实例的一个单独的处理程序。 有关如何选择的更多信息以不同方式之间处理更改,请参见 响应并传播更改

图形表面,并且其他用户界面控件是可以由存储事件处理外部资源的示例。

定义存储事件

  1. 选择要监视事件的类型。 有关完整列表,查看 EventManagerDirectory属性。 每个属性对应于事件的类型。 常用的事件类型为:

    • –触发的ElementAdded 模型元素、关系链接、形状或连接时所创建。

    • –触发的 ElementPropertyChanged 何时更改 Normal 字段的特性的值。 ,只有在新值和旧值不相等,该事件触发。 事件不能应用于计算的和自定义存储属性。

      它不能应用于对应于关系链接的角色。 相反,应使用 ElementAdded 监视域关系。

    • ElementDeleted –触发在一个模型元素后,关系、形状或连接已删除。 您仍然可以访问该元素的属性值,但是,它不会有任何其他元素的关系。

  2. 添加 TheDslDocData 的分部类定义在 DslPackage 项目的一个单独的代码文件。

  3. 编写事件的代码作为一个方法,如下面的示例所示。 ,除非您要访问 DocData,它可以是 static。

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

}

使用做的事件生成不的调整。存储

存储事件不会传播存储内的更改,通常使用,因为事件处理程序执行,在事务完成后对 相反,您将使用存储规则。 有关更多信息,请参见 规则在模型内部传播更改

但是,因此,如果您希望用户能够分别撤消其他的更新与原始事件时,可以使用事件处理程序进行其他更新到存储。 例如,假设小写字母是相册标题的常用约定。 您可以编写更正标题为小写的存储事件处理程序,在用户键入了为大写之后。 但是,用户可以使用取消命令撤消该更正,还原大写字符。 第二 Undo 将移除用户的更改。

相反,因此,如果您编写了单元规则执行相同的操作,用户的更改并将更正在同一事务,这样,用户无法撤消该调整不丢失原始更改。

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 避免对模型元素的更改取消。 事务管理器将将所有内容。存储到其原始状态。

  • 使用 store.InSerializationTransaction 避免进行更改,当模型从文件中加载。

  • 更改会导致进一步事件触发。 确保避免无限循环。

存储事件类型

每个事件类型对应于 Store.EventManagerDirectory 的集合。 您可以随时添加或移除事件处理程序,但是,它是通常的添加这些文档时,加载时。

EventManagerDirectory 属性名称

执行,当

ElementAdded

域类、域关系、形状、链接或关系图创建一个实例。

ElementDeleted

一个模型元素从存储的元素目录中移除并不再是任何关系的源或目标。 该组件从内存实际上,不会删除,但是在将来的情况下保留撤消。

ElementEventsBegun

调用在一个外部事务末尾。

ElementEventsEnded

调用,而其他所有事件处理。

ElementMoved

一个模型元素从一个存储分区移动到另一个。

这与形状的位置相关在关系图上。

ElementPropertyChanged

字段的特性的值已更改。 ,仅当旧值和新值不相等,则执行。

RolePlayerChanged

两个角色 (端) 之一的关系引用新元素。

RolePlayerOrderChanged

在具有显着重数的一个角色大于 1,链接序列已更改。

TransactionBeginning

TransactionCommitted

TransactionRolledBack

请参见

其他资源

响应并传播更改

Sample code: Circuit Diagrams