Event Aggregator

Prism库提供了一种事件机制,可以在应用程序中松散耦合的组件之间进行通信。该机制基于事件聚合器服务,允许发布者和订阅者通过事件进行通信,但仍然没有彼此直接引用。

EventAggregator提供多种发布/订阅功能。这意味着可以有多个发布者引发相同的事件,并且可以有多个订阅者收听同一事件。考虑使用EventAggregator跨模块发布事件以及在业务逻辑代码(如控制器和演示者)之间发送消息时。

使用Prism Library创建的事件是键入的事件。这意味着您可以在运行应用程序之前利用编译时类型检查来检测错误。在Prism Library中,EventAggregator允许订阅者或发布者定位特定的EventBase。事件聚合器还允许多个发布者和多个订阅者,如下图所示。

视频教程

[Using the Event Aggregator视频教程](Prism.assets/Prism - Using the Event Aggregator.mp4)

IEventAggregator

EventAggregator类被提供作为在容器中的服务,并且可以通过检索IEventAggregator界面。事件聚合器负责定位或构建事件以及保留系统中事件的集合。

public interface IEventAggregator
{
TEventType GetEvent<TEventType>() where TEventType : EventBase;
}

如果EventAggregator事件尚未构造,则在第一次访问时构造事件。这使发布者或订阅者无需确定事件是否可用。

PubSubEvent

连接发布者和订阅者的真正工作是由PubSubEvent班级完成的。EventBase是Prism Library中包含的类的唯一实现。此类维护订户列表并处理订阅者的事件调度。

PubSubEvent类是一个通用类,需要将其定义为一般类型的有效载荷类型。这有助于在编译时强制发布者和订阅者提供成功事件连接的正确方法。以下代码显示了PubSubEvent类的部分定义。

创建一个事件

PubSubEvent<TPayload>意图是为应用程序或模块的特定事件的基类。TPayLoad是事件的有效负载的类型。有效负载是在事件发布时将传递给订阅者的参数。

例如,以下代码显示了TickerSymbolSelectedEvent。有效负载是包含公司符号的字符串。请注意此类的实现是如何为空。

public class TickerSymbolSelectedEvent : PubSubEvent<string>{}
注意

在复合应用程序中,事件经常在多个模块之间共享,因此它们在公共位置定义。通常的做法是在共享程序集中定义这些事件,例如“核心”或“基础结构”项目。

发布事件

发布者通过从EventAggregator调用Publish方法中检索事件来引发事件。要访问EventAggregator,可以通过向IEventAggregator类构造函数添加类型参数来使用依赖项注入。

public class MainPageViewModel
{
IEventAggregator _eventAggregator;
public MainPageViewModel(IEventAggregator ea)
{
_eventAggregator = ea;
}
}

以下代码演示了如何发布TickerSymbolSelectedEvent。

_eventAggregator.GetEvent<TickerSymbolSelectedEvent>().Publish("STOCK0");

订阅事件

订阅者可以使用类中Subscribe可用的方法重载之一来参与事件PubSubEvent

public class MainPageViewModel
{
public MainPageViewModel(IEventAggregator ea)
{
ea.GetEvent<TickerSymbolSelectedEvent>().Subscribe(ShowNews);
} void ShowNews(string companySymbol)
{
//implement logic
}
}

有几种订阅方式PubSubEvents。使用以下标准来帮助确定最适合您需求的选项:

  • 如果您需要能够在收到事件时更新UI元素,请订阅以在UI线程上接收事件。
  • 如果您需要过滤事件,请在订阅时提供过滤器委托。
  • 如果您对事件有性能问题,请考虑在订阅时使用强引用的委托,然后手动取消订阅PubSubEvent。
  • 如果以上都不适用,请使用默认订阅。

以下部分描述了这些选项。

在UI线程订阅

订阅者通常需要更新UI元素以响应事件。在WPF中,只有UI线程可以更新UI元素。

默认情况下,订阅者在发布者的线程上接收事件。如果发布者从UI线程发送事件,则订阅者可以更新UI。但是,如果发布者的线程是后台线程,则订阅者可能无法直接更新UI元素。在这种情况下,订户需要使用Dispatcher类在UI线程上安排更新。

PubSubEvent具有棱镜图书馆可以通过允许用户自动接收UI线程上的事件协助。订阅者在订阅期间指示此信息,如以下代码示例所示。

public class MainPageViewModel
{
public MainPageViewModel(IEventAggregator ea)
{
ea.GetEvent<TickerSymbolSelectedEvent>().Subscribe(ShowNews, ThreadOption.UIThread);
} void ShowNews(string companySymbol)
{
//implement logic
}
}

以下选项适用于ThreadOption

  • PublisherThread:使用此设置在发布商的主题上接收活动。这是默认设置。
  • BackgroundThread:使用此设置在.NET Framework线程池线程上异步接收事件。
  • UIThread:使用此设置在UI线程上接收事件。

注意

为了PubSubEvent在UI线程上发布给订阅者,EventAggregator最初必须在UI线程上构建。

订阅过滤

订阅者可能不需要处理已发布事件的每个实例。在这些情况下,订户可以使用过滤器参数。filter参数是类型的,System.Predicate<TPayLoad>并且是在发布事件时执行的委托,以确定已发布事件的有效负载是否与调用订阅者回调所需的一组条件匹配。如果有效负载不满足指定的条件,则不执行订户回调。

通常,此过滤器作为lambda表达式提供,如以下代码示例所示。

public class MainPageViewModel
{
public MainPageViewModel(IEventAggregator ea)
{
TickerSymbolSelectedEvent tickerEvent = ea.GetEvent<TickerSymbolSelectedEvent>();
tickerEvent.Subscribe(ShowNews, ThreadOption.UIThread, false,
companySymbol => companySymbol == "STOCK0");
} void ShowNews(string companySymbol)
{
//implement logic
}
}
注意

Subscribe方法返回一个类型的订阅令牌Prism.Events.SubscriptionToken,可用于稍后删除对该事件的订阅。当您使用匿名委托或lambda表达式作为回调委托时,或者使用不同的过滤器订阅相同的事件处理程序时,此标记特别有用。

注意

建议不要在回调委托中修改有效负载对象,因为多个线程可能同时访问有效负载对象。您可以使有效负载不可变,以避免并发错误。

使用强引用订阅

如果您在短时间内提出多个事件并注意到它们的性能问题,则可能需要使用强委托引用进行订阅。如果您这样做,则需要在处置订户时手动取消订阅该事件。

默认情况下,PubSubEvent维护对订阅者处理程序的弱委托引用并对订阅进行过滤。这意味着PubSubEvent保留的引用不会阻止订户的垃圾收集。使用弱委托引用可以使订户免于取消订阅并允许正确的垃圾收集。

但是,维护此弱委托引用比相应的强引用要慢。对于大多数应用程序,此性能不会很明显,但如果您的应用程序在短时间内发布大量事件,则可能需要对PubSubEvent使用强引用。如果您确实使用了强委托引用,则订阅者应该取消订阅,以便在不再使用订阅对象时启用正确的垃圾回收。

要使用强引用进行订阅,请使用方法keepSubscriberReferenceAlive上的参数Subscribe,如以下代码示例所示。

public class MainPageViewModel
{
public MainPageViewModel(IEventAggregator ea)
{
bool keepSubscriberReferenceAlive = true;
TickerSymbolSelectedEvent tickerEvent = ea.GetEvent<TickerSymbolSelectedEvent>();
tickerEvent.Subscribe(ShowNews, ThreadOption.UIThread, keepSubscriberReferenceAlive,
companySymbol => companySymbol == "STOCK0");
} void ShowNews(string companySymbol)
{
//implement logic
}
}

keepSubscriberReferenceAlive参数的类型的bool

  • 设置为时true,事件实例保留对订户实例的强引用,从而不允许它收集垃圾。有关如何取消订阅的信息,请参阅本主题后面的“取消订阅事件”一节。
  • 当设置为false(省略此参数时的默认值)时,事件维护对订户实例的弱引用,从而允许垃圾收集器在没有其他引用时配置订阅者实例。收集订户实例后,将自动取消订阅该事件。

取消事件订阅

如果您的订户不再想要接收活动,您可以使用订阅者的处理程序取消订阅,也可以使用订阅令牌取消订阅。

以下代码示例演示如何直接取消订阅处理程序。

public class MainPageViewModel
{
TickerSymbolSelectedEvent _event;
public MainPageViewModel(IEventAggregator ea)
{
_event = ea.GetEvent<TickerSymbolSelectedEvent>();
_event.Subscribe(ShowNews);
} void Unsubscribe()
{
_event.Unsubscribe(ShowNews);
} void ShowNews(string companySymbol)
{
//implement logic
}
}

以下代码示例演示如何取消订阅订阅令牌。令牌作为方法的返回值提供Subscribe

public class MainPageViewModel
{
TickerSymbolSelectedEvent _event;
SubscriptionToken _token;
public MainPageViewModel(IEventAggregator ea)
{
_event = ea.GetEvent<TickerSymbolSelectedEvent>();
_token = _event.Subscribe(ShowNews);
} void Unsubscribe()
{
_event.Unsubscribe(_token);
} void ShowNews(string companySymbol)
{
//implement logic
}
}

Prism_Event Aggregator(4)的更多相关文章

  1. Metasploit中aggregator插件无法使用

    Metasploit中aggregator插件无法使用   aggregator是Metasploit自带的一个插件,用来管理会话Session.该插件使用metasploit-aggreator库. ...

  2. 优化之Aggregator组件

    Aggregator组件通常会降低性能,因为它们必须在处理数据之前对数据进行分组 Aggregator组件需要额外的内存来保存中间组结果 通过如下方式对Aggregator组件进行优化 简化group ...

  3. Informatica 常用组件Aggregator之四 创建聚合转换

    在 Mapping Designer 中选择"转换-创建".选择聚合转换. 为聚合输入一个名称,并单击"创建".然后单击"完成". Desi ...

  4. 【spring cloud】spring cloud打包最外层项目报错:'packaging' with value 'jar' is invalid. Aggregator projects require 'pom' as packaging. @ line 9, column 13

    OK,spring cloud项目,最外层的父级项目在打包的时候,报错如下: "C:\Program Files\Java\jdk1.8.0_131\bin\java" -Dmav ...

  5. WPF MVVM 从Prism中学习设计模式之Event Aggregator 模式

    Prism简介 Prism是由微软Patterns & Practices团队开发的项目,目的在于帮助开发人员构建松散耦合的.更灵活.更易于维护并且更易于测试的WPF应用或是Silverlig ...

  6. Event Aggregator

    /** * Created with JetBrains WebStorm. * User: 宇乔 * Date: 13-8-2 * Time: 下午3:01 * To change this tem ...

  7. Informatica 常用组件Aggregator之三 使用排序输入

    可以使用排序输入选项改善聚合转换性能.使用排序输入时,PowerCenter 会假定所有数据已按组排序.PowerCenter 读取某组的行时,它将执行聚合计算.需要时,它会将组信息存储在存储器中.要 ...

  8. Informatica 常用组件Aggregator之二 分组依据端口

    聚合转换允许您为聚合定义组,而不是在所有的输入数据间执行聚合.例如,您可以查找按地区分组的总销量,而不是查找总的公司销量. 要为聚合表达式定义组,请选择聚合转换中的相应输入.输入/输出.输出和变量端口 ...

  9. Informatica 常用组件Aggregator之一 聚合表达式

    转换类型:已连接.主动        聚合转换允许您执行聚合计算,比如平均值和总和.聚合转换与表达式转换不同,您可以使用聚合转换对多组执行计算.而表达式转换只允许您逐行地执行计算.        使用 ...

随机推荐

  1. vue反向代理(解决跨域)

    1,vue中有提供反向代理的接口,就是config/index.js中的proxyTable,我的脚手架版本是2.9.6,proxyTable配置初始为空,如下图. 2,将proxyTable配置如下 ...

  2. Spring Data初步--整合Hibernate

    Spring Data课程中的技术介绍 Hibernate: Hibernate 是一个开放源代码的对象关系映射框架,它对 JDBC 进行了非常轻量级的对象封装,它将 pojo 与数据库表建立映射关系 ...

  3. CF547E Milk and Friends(AC自动机的fail指针上建主席树 或 广义后缀自动机的parent线段树合并)

    What-The-Fatherland is a strange country! All phone numbers there are strings consisting of lowercas ...

  4. HDU-1027Ignatius and princess II

    Now our hero finds the door to the BEelzebub feng5166. He opens the door and finds feng5166 is about ...

  5. Dubbo加权轮询负载均衡的源码和Bug,了解一下?

    本文是对于Dubbo负载均衡策略之一的加权随机算法的详细分析.从2.6.4版本聊起,该版本在某些情况下存在着比较严重的性能问题.由问题入手,层层深入,了解该算法在Dubbo中的演变过程,读懂它的前世今 ...

  6. 基于STM32 HID 游戏手柄开发调试

    stm32自带usb接口,非常适合做hid设备,免驱开发也很方便. 使用stm32通过正确的报告描述符配置后,插入usb,电脑正确识别如下(设备和打印机) 可以通过右键,游戏控制器设置 通过选择属性 ...

  7. 【JS】328- 8个你不知道的DOM功能

    最近一直在关注工具,从 React 和 npm-install-everything 中休息一下,看看一些原生的 DOM 和 Web API 的功能,他们可以在没有任何依赖库的浏览器中直接运行. 这篇 ...

  8. ES6,箭头函数 (=>)注意点

    函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象. 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误. 不可以使用arguments对象,该对象在函数体内不存 ...

  9. 使用 yum 安装Docker(CentOS 7下)

    使用 yum 安装(CentOS 7下) Docker 要求 CentOS 系统的内核版本高于 3.10 ,查看本页面的前提条件来验证你的CentOS 版本是否支持 Docker . 通过 uname ...

  10. 关于页面打印window.print()的样式问题

    当我们打印网页的时候.有时候会发现.打印出来的.跟网页上看到的样式的差别有点大.这其中可能有的问题是.样式问题. 当调用打印(window.print())方法时.打印机会在网页的样式中查找 @med ...