从 PRISM 开始学 WPF(一)WPF?
从 PRISM 开始学 WPF(二)Prism?
从 PRISM 开始学 WPF(三)Prism-Region?
从 PRISM 开始学 WPF(四)Prism-Module?
从 PRISM 开始学 WPF(五)MVVM(一)ViewModel?
从 PRISM 开始学 WPF(六)MVVM(二)Command?
事件聚合器 EventAggregator
Event aggregation. For communication across view models, presenters, or controllers when there is not a direct action-reaction expectation.
(﹏),Google 一下:
事件聚合在没有直接的行动反应期望的情况下, 跨视图模型, 演示者或控制者进行通信
1 是没有直接行动反应期望, 2 跨视图通信
在具体了解这个概念之前, 先看一个例子:
通过简介, 很容易想到聊天窗口, 当你在一个视图 A 中输入文字点击发送之后, 另外一个视图 B 会接收到这个消息, 并将文字输出到屏幕上, 而这个时候, 视图 A 并不关心谁将收到信息, 只管提交, 视图 B 也不管是谁发来的消息, 只管接收, 并显示
关门, 放代码:
Setp1 在 Shell 窗口中, 定义两个 Region, 分别来展示发送视图和接收视图
- <Grid>
- <Grid.ColumnDefinitions>
- <ColumnDefinition />
- <ColumnDefinition />
- </Grid.ColumnDefinitions>
- <ContentControl prism:RegionManager.RegionName="LeftRegion" />
- <ContentControl Grid.Column="1" prism:RegionManager.RegionName="RightRegion" />
- </Grid>
今天 Typora 更新了, 代码块支持 xaml 格式, 以前都是用 xml-dtd, 下面统一使用 xaml
XAML
这应该是教程中出现的比较复杂的 xaml, 比较详细的使用了 Grid, 这里的 Grid 很像一个表格, 在使用他布局之前, 需要定义好列数, 下面的代码为 Grid 设置了两个列
- <Grid.ColumnDefinitions>
- <ColumnDefinition />
- <ColumnDefinition />
- </Grid.ColumnDefinitions>
那么能加行吗? 那是当然的了, 下面是为 Grid 添加两行, Height 的 Auto 表示这个行的高度会根据内容高度进行适应:
- <Grid.RowDefinitions>
- <RowDefinition Height="Auto" />
- <RowDefinition Height="Auto" />
- </Grid.RowDefinitions>
在使用 Grid 的时候, 需要为控件指定 Grid 的位置 Grid.Column="1",1 就是下标, 都是从 0 开始的, 1 就代表第二列, 当你不指定具体位置的时候, 默认将控件插入 Grid 的 0 行 0 列, 上面的 LeftRegion 就是在首行首列的位置
Setp2 新建两个 Module, 分别为 ModuleA 和 ModuleB,ModuleA 中的视图用来发送信息, ModuleB 中的视图用来接收显示信息
Module 的创建在第四节已经说明了
先看 ModuleA 的发送视图:
- MessageView.xaml
- <StackPanel>
- <TextBox Text="{Binding Message}" Margin="5"/>
- <Button Command="{Binding SendMessageCommand}" Content="Send Message" Margin="5"/>
- </StackPanel>
MessageView 中定义了一个文本框, 进行了数据绑定, 然后是一个按钮, 绑定了一个 SendMessageCommand 命令在我们点击 Send Message 按钮的时候, 就会将 Message 显示到接收视图里去
再看 ModuleB 的显示视图:
- MessageList.xaml
- <Grid>
- <ListBox ItemsSource="{Binding Messages}" />
- </Grid>
就定义了一个 ListBox 来显示 MessageItemsSource 绑定的应该是一个集合, 不然怎么叫 Source 呢?
接下来, 看下 Prism 怎么实现跨视图模型通讯:
首先, 定义一个 MessageSentEvent 类, 继承
PubSubEvent<string>
,string 是因为这个事件接收的 payload 是字符串类型, PubSubEvent<T > 类负责连接发布者和订阅者, 他负责维护订阅者列表并处理事件派发给订阅者
- using Prism.Events;
- namespace UsingEventAggregator.Core
- {
- public class MessageSentEvent : PubSubEvent<string>
- {
- }
- }
然后我们看下 MessageViewModel:
- using Prism.Commands;
- using Prism.Events;
- using Prism.Mvvm;
- using UsingEventAggregator.Core;
- namespace ModuleA.ViewModels {
- public class MessageViewModel: BindableBase {
- IEventAggregator _ea;
- private string _message = "Message to Send";
- public string Message {
- get {
- return _message;
- }
- set {
- SetProperty(ref _message, value);
- }
- }
- public DelegateCommand SendMessageCommand {
- get;
- private set;
- }
- public MessageViewModel(IEventAggregator ea) {
- _ea = ea;
- SendMessageCommand = new DelegateCommand(SendMessage);
- }
- private void SendMessage() {
- _ea.GetEvent <MessageSentEvent> ().Publish(Message);
- }
- }
- }
先看我们熟悉的部分:
- private string _message = "Message to Send";
- public string Message
- {
- get { return _message; }
- set { SetProperty(ref _message, value); }
- }
这是
<TextBox Text="{Binding Message}" Margin="5"/>
中的 Message
然后定义了一个 DelegateCommand
public DelegateCommand SendMessageCommand { get; private set; }
接下来就是 EventAggregator 部分了:
首先定义一个 IEventAggregator:
IEventAggregator _ea;
构造函数:
ea 是依赖注入容器提供的 EventAggregator 实例, 还定义了命令 SendMessageCommand 的回调函数 SendMessage
- public MessageViewModel(IEventAggregator ea)
- {
- _ea = ea;
- SendMessageCommand = new DelegateCommand(SendMessage);
- }
SendMessge 中通过 MessageSentEvent 发布 Payload, 这里 Payload 一定要匹配 MessageSentEvent 的 Payload 类型, 上面我们继承
PubSubEvent<string>
时使用的 String, 不然的话, 这在编译的时候就会抛出异常
- private void SendMessage()
- {
- _ea.GetEvent<MessageSentEvent>().Publish(Message);
- }
接下来, 我们让 ModuleB 中的
MessageListViewModel
获取这个 Payload, 并进行一些操作:
- using Prism.Events;
- using Prism.Mvvm;
- using System.Collections.ObjectModel;
- using UsingEventAggregator.Core;
- namespace ModuleB.ViewModels
- {
- public class MessageListViewModel : BindableBase
- {
- IEventAggregator _ea;
- private ObservableCollection<string> _messages;
- public ObservableCollection<string> Messages
- {
- get { return _messages; }
- set { SetProperty(ref _messages, value); }
- }
- public MessageListViewModel(IEventAggregator ea)
- {
- _ea = ea;
- Messages = new ObservableCollection<string>();
- _ea.GetEvent<MessageSentEvent>().Subscribe(MessageReceived);
- }
- private void MessageReceived(string message)
- {
- Messages.Add(message);
- }
- }
- }
代码阅读:
- private ObservableCollection<string> _messages;
- public ObservableCollection<string> Messages
- {
- get { return _messages; }
- set { SetProperty(ref _messages, value); }
- }
这是
<ListBox ItemsSource="{Binding Messages}" />
中的 Messages, 他的类型是
ObservableCollection
, 具体为什么是 ObservableCollection 而不是 List! 后面再说
- public MessageListViewModel(IEventAggregator ea)
- {
- _ea = ea;
- Messages = new ObservableCollection<string>();
- _ea.GetEvent<MessageSentEvent>().Subscribe(MessageReceived);
- }
这里订阅了 MessageSentEvent, 并且处理 Payload, 处理 Payload 的方法是 MessageReceived, 这个方法在 Messages 新增一条记录
事件聚合器可以有多个发布者和多个订阅者
来源: https://www.cnblogs.com/hicolin/p/8707903.html