步骤:

  1. 继承PubSubEvent<T>创建自定义事件类型
  2. 创建事件发送者
  3. 创建事件接收者,并订阅指定的事件

1. 事件聚合器

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

事件聚合器提供多播发布/订阅功能。这意味着可以有多个发布者引发相同的事件,并且可以有多个订阅者监听相同的事件。

通过事件聚合器服务可以使用IEventAggregator接口获取到事件聚合器。事件聚合器负责定位或构建事件,并在系统中保存事件的集合。首次访问一个事件时,如果该事件尚未构建,则构建。

2. 事件类型

PubSubEventPrism中对积累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. 样例

创建一个名为EventAggregatorAppWPF应用程序项目,并在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>();}}
}
  • 创建 ViewsViewModels文件夹,并将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.xamlPublisherView.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.xamlSubscriberView.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文件夹中,新建名称为MainWindowViewModelPublisherViewModelSubscriberViewModel 三个类,源码分别如下:
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;}}
}
  • 在项目层级下,新建MessageSentEventPublisherModuleSubscriberModule三各类,源码分别如下:
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)相关推荐

  1. 事件聚合器 - Caliburn.Micro 文档系列

    文章目录 事件聚合器 (Event Aggregator) 入门 创建与生命周期 发布事件 使用自定义线程发布事件 订阅事件 订阅许多事件 多态的订阅者 查询处理程序 协同感知订阅者 任务感知订阅者 ...

  2. 从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator?

    从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator? 原文:从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator? 从PRISM开始学 ...

  3. .NET Core 3 WPF MVVM框架 Prism系列之事件聚合器

    本文将介绍如何在.NET Core3环境下使用MVVM框架Prism的使用事件聚合器实现模块间的通信 一.事件聚合器  在上一篇 .NET Core 3 WPF MVVM框架 Prism系列之模块化 ...

  4. c#事件的发布-订阅模型_NET Core 3 WPF MVVM框架 Prism系列之事件聚合器

    本文将介绍如何在.NET Core3环境下使用MVVM框架Prism的使用事件聚合器实现模块间的通信 一.事件聚合器#  在上一篇 .NET Core 3 WPF MVVM框架 Prism系列之模块化 ...

  5. prism EventAggregator(事件聚合器)

    1 根据<prism 搭建项目>搭建Prism项目 2 新建类库项目Prism.UseEventAggregator,创建MessageSentEvent类,使其继承于PubSubEven ...

  6. mysql事件调度定时任务_详解MySQL用事件调度器Event Scheduler创建定时任务

    前言 事件调度器相当于操作系统中的定时任务(如:Linux中的cron.Window中的计划任务),但MySql的事件调度器可以精确到秒,对于一些实时性要求较高的数据处理非常有用. 1. 创建/修改事 ...

  7. (十三)事件分发器——event()函数,事件过滤

    事件分发器--event()函数 事件过滤 事件进入窗口之前被拦截 eventFilter #include "mywidget.h" #include "ui_mywi ...

  8. mysql 事件 day hour_Mysql事件调度器(Event Scheduler)

    Mysql中的事件调度器Event Scheduler类似于linux下的crontab计划任务的功能,它是由一个特殊的时间调度线程执行的 一.查看当前是否开启了event scheduler三种方法 ...

  9. Caliburn.Micro使用事件聚合器

    Caliburn.Micro框架使用观察者模式实现了事件聚合器 Caliburn.Micro对参数采用强类型的方式,相比MvvmLight算是省心,易用 详细的说明参见官方文档https://cali ...

最新文章

  1. 吴恩达新课发布1天,引3万人观看 | 完整PPT
  2. JAVA基础5——与String相关的系列(1)
  3. 在做mvc时遇到的一些问题
  4. 把自己编写的python模块添加到PYTHONPATH上
  5. 专访小米欧阳辰:深度揭秘小米广告平台的构建、底层模块和坑
  6. 王爽汇编语言实验7一个很好的解法(转)
  7. 1在mysql进行定义操作系统_Mysql基础知识一
  8. 微信公众平台开发——问题篇
  9. matlab柱状斜线_Matlab小练习:按斜线方向依次赋值矩阵
  10. word List 49
  11. 动态规划-01背包问题详解
  12. php pdo更新,php - 使用PDO和MySQL更新查询
  13. 步骤一:入门Linux基础\01.Linux 简介和安装\第2章 Ubuntu系统的安装
  14. 【深度学习基本概念】上采样、下采样、卷积、池化
  15. BT5的 U盘启动 制作
  16. 教师资格证报名网页打不开,解决新版IE浏览器无法打开教师资格证页面问题(不需要添加兼容性站点!)
  17. 极客时间前端进阶特训营winter、杨村长、然叔、高少云,《精通React》大专栏,React低代码项目,前端算法实战,杨村长Vue3开源组件库实战(Vue3+Vite+VitePress+TSX+T
  18. Biometric Framework overview (生物识别框架概述)
  19. D 语言编写CGI程序
  20. 【HTTP】HTPP学习笔记

热门文章

  1. SQLite 附加数据库
  2. 【小黑JavaScript入门系列之脑力训练一《一阶段练习剩余合集》】
  3. viewpager+fragment避免每次都重新加载
  4. 传统图像分割——区域合并算法(region merging)
  5. D. Fragmentation merging
  6. mysql单精度与双精度_单精度与双精度的区别
  7. JavaWeb之面向故事学习
  8. p2p内网穿透技术-udp打洞
  9. SpringCloud Gateway——请求转发源码分析
  10. JSP页面forEach使用