【Prism 8】事件聚合器(Event Aggregator)
步骤:
- 继承
PubSubEvent<T>
创建自定义事件类型- 创建事件发送者
- 创建事件接收者,并订阅指定的事件
1. 事件聚合器
Prism
提供了一种机制,可以实现应用程序中松散耦合组件之间的通信
。这种机制基于事件聚合器服务
,允许发布者和订阅者通过事件进行通信,并且彼此之间仍然没有直接引用。
事件聚合器提供多播
发布/订阅功能。这意味着可以有多个发布者引发相同的事件,并且可以有多个订阅者监听相同的事件。
通过事件聚合器服务
可以使用IEventAggregator
接口获取到事件聚合器。事件聚合器负责定位或构建事件,并在系统中保存事件的集合。首次访问一个事件时,如果该事件尚未构建,则构建。
2. 事件类型
PubSubEvent
是Prism
中对积累EventBase
的唯一实现。此类维护订阅者列表并向订阅者发送事件。PubSubEvent
是一个泛型类,在使用时需要指定具体类型以进行特化。
一般是通过继承该类,特化一个自定义事件类型
3. 发布
发布者通过事件聚合器服务获取到EventAggregator
,并调用Publish
方法来触发事件。
4. 订阅
订阅者通过事件聚合器服务获取到EventAggregator
,并调用Subscribe
方法进行注册。之后,注册的事件被触发是,通过参数指定委托进行相应。
4.1 订阅类型
- ThreadOption.PublisherThread 与发布者使用相同线程,默认方式
- ThreadOption.BackgroundThread 使用线程池线程
- ThreadOption.UIThread 使用UI线程
4.2 事件过滤
订阅者在注册事件订阅是可以通过参数指定过滤的事件条件,只有满足条件的事件才能被订阅者真正使用。过滤通过System.Predicate<T>
委托进行。
4.3 强引用订阅
默认情况下使用弱引用
方式。强引用调用能够加速事件的传递,但必须手动的取消订阅。
5. 样例
创建一个名为EventAggregatorApp
的WPF应用程序
项目,并在Nuget
中安装Prism.Unity
,此处使用的版本为8.1.97
。
- 打开
App.xaml
,修改为如下内容:
<unity:PrismApplicationx:Class="EventAggregatorApp.App"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:unity="http://prismlibrary.com/"><Application.Resources />
</unity:PrismApplication>
- 打开
App.xaml.cs
,修改为如下内容:
using System.Windows;
using EventAggregatorApp.Views;
using Prism.Ioc;
using Prism.Modularity;namespace EventAggregatorApp
{public partial class App{protected override void RegisterTypes(IContainerRegistry containerRegistry){}protected override Window CreateShell(){return this.Container.Resolve<MainWindowView>();}protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog){moduleCatalog.AddModule<PublisherModule>();moduleCatalog.AddModule<SubscriberModule>();}}
}
- 创建
Views
与ViewModels
文件夹,并将MainWindow.xaml
重命名为MainWindowViewModel.xaml
,最后将MainWindowViewModel.xaml
移动到Views
文件夹 - 打开
MainWindowViewModel.xaml
,修改为如下内容:
<Windowx:Class="EventAggregatorApp.Views.MainWindowView"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:prism="http://prismlibrary.com/"xmlns:viewModels="clr-namespace:EventAggregatorApp.ViewModels"Title="{Binding Title}"Width="600"Height="480"d:DataContext="{d:DesignInstance viewModels:MainWindowViewModel}"prism:ViewModelLocator.AutoWireViewModel="True"mc:Ignorable="d"><DockPanel><ContentControl prism:RegionManager.RegionName="LeftRegion" DockPanel.Dock="Top" /><BorderHeight="3"Background="LightGray" Margin="5"DockPanel.Dock="Top" /><ContentControl prism:RegionManager.RegionName="RightRegion" /></DockPanel>
</Window>
- 打开
MainWindowViewModel.xaml.cs
,修改为如下内容:
namespace EventAggregatorApp.Views
{public partial class MainWindowView{public MainWindowView(){this.InitializeComponent();}}
}
- 在
Views
文件夹下,新建名称为PublisherView
的用户自定义控件,并修改PublisherView.xaml
与PublisherView.xaml.cs
内容如下:
<UserControlx:Class="EventAggregatorApp.Views.PublisherView"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:prism="http://prismlibrary.com/"xmlns:viewModels="clr-namespace:EventAggregatorApp.ViewModels"d:DataContext="{d:DesignInstance viewModels:PublisherViewModel}"prism:ViewModelLocator.AutoWireViewModel="True"mc:Ignorable="d"><StackPanel><BorderMargin="5"Background="LightGreen"CornerRadius="5"><TextBlockMargin="5"HorizontalAlignment="Center"FontSize="20"FontWeight="Bold">发送者</TextBlock></Border><TextBox Margin="5" Text="{Binding Message}" /><ButtonMargin="5"Command="{Binding SendMessageCommand}"Content="发送" /></StackPanel>
</UserControl>
namespace EventAggregatorApp.Views
{public partial class PublisherView{public PublisherView(){this.InitializeComponent();}}
}
- 在
Views
文件夹下,新建名称为SubscriberView
的用户自定义控件,并修改SubscriberView.xaml
与SubscriberView.xaml.cs
内容如下:
<UserControlx:Class="EventAggregatorApp.Views.SubscriberView"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:prism="http://prismlibrary.com/"xmlns:viewModels="clr-namespace:EventAggregatorApp.ViewModels"d:DataContext="{d:DesignInstance viewModels:SubscriberViewModel}"prism:ViewModelLocator.AutoWireViewModel="True"mc:Ignorable="d"><DockPanel><BorderMargin="5"Background="LightGreen"CornerRadius="5"DockPanel.Dock="Top"><TextBlockMargin="5"HorizontalAlignment="Center"FontSize="20"FontWeight="Bold">Subscriber</TextBlock></Border><UniformGridMargin="5,2"Columns="4"DockPanel.Dock="Top"><TextBlock>订阅线程类型</TextBlock><RadioButton Margin="3,0" IsChecked="{Binding IsPublisherThread}">Publisher</RadioButton><RadioButton Margin="3,0" IsChecked="{Binding IsBackgroundThread}">Background</RadioButton><RadioButton Margin="3,0" IsChecked="{Binding IsUiThread}">UI</RadioButton></UniformGrid><DockPanel Margin="5,2" DockPanel.Dock="Top"><TextBlock Margin="0,0,10,0">是否为强类型订阅</TextBlock><CheckBox VerticalAlignment="Center" IsChecked="{Binding IsStrongReference}"/></DockPanel><UniformGrid Columns="2" DockPanel.Dock="Top"><Button Margin="5, 2" Command="{Binding SubscribeCommand}">注册订阅</Button><Button Margin="5, 2" Command="{Binding UnsubscribeCommand}">取消订阅</Button></UniformGrid><ListBox Margin="5" ItemsSource="{Binding MsgCollection}" /></DockPanel>
</UserControl>
namespace EventAggregatorApp.Views
{public partial class SubscriberView{public SubscriberView(){this.InitializeComponent();}}
}
- 在
ViewModels
文件夹中,新建名称为MainWindowViewModel
、PublisherViewModel
和SubscriberViewModel
三个类,源码分别如下:
using Prism.Mvvm;namespace EventAggregatorApp.ViewModels
{public class MainWindowViewModel : BindableBase{private string title = "EventAggregator";public string Title{get => this.title;set => this.SetProperty(ref this.title, value);}}
}
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;namespace EventAggregatorApp.ViewModels
{public class PublisherViewModel : BindableBase{private readonly IEventAggregator eventAggregator;private string message = "Send a message form publisher to subscriber";private DelegateCommand sendMessageCommand;public PublisherViewModel(IEventAggregator eventAggregator){this.eventAggregator = eventAggregator;}public string Message{get => this.message;set => this.SetProperty(ref this.message, value);}public DelegateCommand SendMessageCommand => this.sendMessageCommand ?? (this.sendMessageCommand = new DelegateCommand(() => this.eventAggregator.GetEvent<MessageSentEvent>().Publish(this.Message)));}
}
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using System.Collections.ObjectModel;
using System.Threading;namespace EventAggregatorApp.ViewModels
{public class SubscriberViewModel : BindableBase{private ObservableCollection<string> msgCollection;public ObservableCollection<string> MsgCollection{get => this.msgCollection;set => this.SetProperty(ref this.msgCollection, value);}private bool isPublisherThread = true;public bool IsPublisherThread{get => this.isPublisherThread;set => this.SetProperty(ref this.isPublisherThread, value);}private bool isBackgroundThread;public bool IsBackgroundThread{get => this.isBackgroundThread;set => this.SetProperty(ref this.isBackgroundThread, value);}private bool isUiThread;public bool IsUiThread{get => this.isUiThread;set => this.SetProperty(ref this.isUiThread, value);}private bool isStrongReference;public bool IsStrongReference{get => this.isStrongReference;set => this.SetProperty(ref this.isStrongReference, value);}private DelegateCommand subscribeCommand;public DelegateCommand SubscribeCommand => this.subscribeCommand ?? (this.subscribeCommand = new DelegateCommand(this.SubscribeEvent));private void SubscribeEvent(){var threadOption = ThreadOption.PublisherThread;if (this.isBackgroundThread){threadOption = ThreadOption.BackgroundThread;}if (this.isUiThread){threadOption = ThreadOption.UIThread;}this.eventAggregator.GetEvent<MessageSentEvent>().Subscribe(this.ShowMessage,threadOption,this.isStrongReference,msg=>!msg.StartsWith("#"));this.msgCollection.Add($"ThreadOption: {threadOption}, StrongRef: {this.isStrongReference}");}private DelegateCommand unsubscribeCommand;public DelegateCommand UnsubscribeCommand => this.unsubscribeCommand ?? (this.unsubscribeCommand = new DelegateCommand(() =>{this.eventAggregator.GetEvent<MessageSentEvent>().Unsubscribe(this.ShowMessage);this.msgCollection.Add("订阅已取消");}));private void ShowMessage(string msg){if (this.synchronizationContext != null && this.mainThreadId != Thread.CurrentThread.ManagedThreadId){this.synchronizationContext.Post(o =>{this.msgCollection.Add("已跨线程调用");this.msgCollection.Add(msg);}, null);}else{this.msgCollection.Add(msg);}// 这种方式在后台线程时会报错,错误信息为:某个 ItemsControl 与它的项源不一致。// 原因是:在执行try语句块中的代码时,触发了一次的 CollectionChanged 事件,// 然后进入catch语句块,再次触发了两次 CollectionChanged 事件// 总共触发了三次 CollectionChanged 事件,但是集合中项增加的数量为2,造成项的数量与CollectionChanged事件发生的数量不匹配//try//{// this.msgCollection.Add(msg);//}//catch//{// if (this.synchronizationContext != null && this.mainThreadId != Thread.CurrentThread.ManagedThreadId)// {// this.synchronizationContext.Post(o =>// {// this.msgCollection.Add("已跨线程调用");// this.msgCollection.Add(msg);// }, null);// }//}}private readonly int mainThreadId;private readonly SynchronizationContext synchronizationContext;private readonly IEventAggregator eventAggregator;public SubscriberViewModel(IEventAggregator eventAggregator){this.MsgCollection = new ObservableCollection<string>();this.mainThreadId = Thread.CurrentThread.ManagedThreadId;this.eventAggregator = eventAggregator;this.synchronizationContext = SynchronizationContext.Current;}}
}
- 在项目层级下,新建
MessageSentEvent
、PublisherModule
与SubscriberModule
三各类,源码分别如下:
using Prism.Events;namespace EventAggregatorApp
{public class MessageSentEvent : PubSubEvent<string>{}
}
using EventAggregatorApp.Views;
using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;namespace EventAggregatorApp
{public class PublisherModule : IModule{public void OnInitialized(IContainerProvider containerProvider){// 获取区域管理器var regionManager = containerProvider.Resolve<IRegionManager>();// 将指定名称的区域与特定类型的视图相关联regionManager.RegisterViewWithRegion("LeftRegion", typeof(PublisherView));}public void RegisterTypes(IContainerRegistry containerRegistry){}}
}
using EventAggregatorApp.Views;
using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;namespace EventAggregatorApp
{public class SubscriberModule : IModule{public void OnInitialized(IContainerProvider containerProvider){var regionManager = containerProvider.Resolve<IRegionManager>();regionManager.RegisterViewWithRegion("RightRegion", typeof(SubscriberView));}public void RegisterTypes(IContainerRegistry containerRegistry){}}
}
- 编译,运行程序,效果如下:
可以在
未订阅
的情况下设置订阅选项
源码下载
【Prism 8】事件聚合器(Event Aggregator)相关推荐
- 事件聚合器 - Caliburn.Micro 文档系列
文章目录 事件聚合器 (Event Aggregator) 入门 创建与生命周期 发布事件 使用自定义线程发布事件 订阅事件 订阅许多事件 多态的订阅者 查询处理程序 协同感知订阅者 任务感知订阅者 ...
- 从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator?
从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator? 原文:从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator? 从PRISM开始学 ...
- .NET Core 3 WPF MVVM框架 Prism系列之事件聚合器
本文将介绍如何在.NET Core3环境下使用MVVM框架Prism的使用事件聚合器实现模块间的通信 一.事件聚合器 在上一篇 .NET Core 3 WPF MVVM框架 Prism系列之模块化 ...
- c#事件的发布-订阅模型_NET Core 3 WPF MVVM框架 Prism系列之事件聚合器
本文将介绍如何在.NET Core3环境下使用MVVM框架Prism的使用事件聚合器实现模块间的通信 一.事件聚合器# 在上一篇 .NET Core 3 WPF MVVM框架 Prism系列之模块化 ...
- prism EventAggregator(事件聚合器)
1 根据<prism 搭建项目>搭建Prism项目 2 新建类库项目Prism.UseEventAggregator,创建MessageSentEvent类,使其继承于PubSubEven ...
- mysql事件调度定时任务_详解MySQL用事件调度器Event Scheduler创建定时任务
前言 事件调度器相当于操作系统中的定时任务(如:Linux中的cron.Window中的计划任务),但MySql的事件调度器可以精确到秒,对于一些实时性要求较高的数据处理非常有用. 1. 创建/修改事 ...
- (十三)事件分发器——event()函数,事件过滤
事件分发器--event()函数 事件过滤 事件进入窗口之前被拦截 eventFilter #include "mywidget.h" #include "ui_mywi ...
- mysql 事件 day hour_Mysql事件调度器(Event Scheduler)
Mysql中的事件调度器Event Scheduler类似于linux下的crontab计划任务的功能,它是由一个特殊的时间调度线程执行的 一.查看当前是否开启了event scheduler三种方法 ...
- Caliburn.Micro使用事件聚合器
Caliburn.Micro框架使用观察者模式实现了事件聚合器 Caliburn.Micro对参数采用强类型的方式,相比MvvmLight算是省心,易用 详细的说明参见官方文档https://cali ...
最新文章
- 吴恩达新课发布1天,引3万人观看 | 完整PPT
- JAVA基础5——与String相关的系列(1)
- 在做mvc时遇到的一些问题
- 把自己编写的python模块添加到PYTHONPATH上
- 专访小米欧阳辰:深度揭秘小米广告平台的构建、底层模块和坑
- 王爽汇编语言实验7一个很好的解法(转)
- 1在mysql进行定义操作系统_Mysql基础知识一
- 微信公众平台开发——问题篇
- matlab柱状斜线_Matlab小练习:按斜线方向依次赋值矩阵
- word List 49
- 动态规划-01背包问题详解
- php pdo更新,php - 使用PDO和MySQL更新查询
- 步骤一:入门Linux基础\01.Linux 简介和安装\第2章 Ubuntu系统的安装
- 【深度学习基本概念】上采样、下采样、卷积、池化
- BT5的 U盘启动 制作
- 教师资格证报名网页打不开,解决新版IE浏览器无法打开教师资格证页面问题(不需要添加兼容性站点!)
- 极客时间前端进阶特训营winter、杨村长、然叔、高少云,《精通React》大专栏,React低代码项目,前端算法实战,杨村长Vue3开源组件库实战(Vue3+Vite+VitePress+TSX+T
- Biometric Framework overview (生物识别框架概述)
- D 语言编写CGI程序
- 【HTTP】HTPP学习笔记