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

从PRISM开始学WPF(一)WPF?

从PRISM开始学WPF(二)Prism?

从PRISM开始学WPF(三)Prism-Region?

从PRISM开始学WPF(四)Prism-Module?

从PRISM开始学WPF(五)MVVM(一)ViewModel?

从PRISM开始学WPF(六)MVVM(二)Command?

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

事件聚合器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来显示Message。ItemsSource绑定的应该是一个集合,不然怎么叫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新增一条记录。

事件聚合器可以有多个发布者和多个订阅者。

作为订阅者,我想订阅特定类型的Payload,上个例子中我只想订阅message里含有Brian的事件,怎么处理呢?Prism为Subscribe方法实现了一个过滤器:

            _ea.GetEvent<MessageSentEvent>().Subscribe(MessageReceived, ThreadOption.PublisherThread, false, (filter) => filter.Contains("Brian"));

过滤器是一个Predicate<TPayload> filter,参考 Predicate

从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator?的更多相关文章

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

    从PRISM开始学WPF(一)WPF? 从PRISM开始学WPF(二)Prism? 从PRISM开始学WPF(三)Prism-Region? 从PRISM开始学WPF(四)Prism-Module? ...

  2. 从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator-更新至Prism7.1

    原文:从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator-更新至Prism7.1 事件聚合器EventAggregator [7.1updated]除了app部分,没 ...

  3. 从PRISM开始学WPF,Prism7更新了什么

    当时我在搬运Prism6.3的sample代码的时候,就是因为网上的资料太老旧,万万没想到这给自己挖了一个坑,因为我在做笔记的时候,prism已经在更新7.0了 现在已经是7.2了,(lll¬ω¬), ...

  4. 从PRISM开始学WPF(一)WPF?

    从PRISM开始学WPF(一)WPF?   我最近打算学习WPF ,在寻找MVVM框架的时候发现了PRISM,在此之前还从一些博客上了解了其他的MVVM框架,比如浅谈WPF中的MVVM框架--MVVM ...

  5. 从PRISM开始学WPF(一)WPF-更新至Prism7.1

    原文:从PRISM开始学WPF(一)WPF-更新至Prism7.1 我最近打算学习WPF ,在寻找MVVM框架的时候发现了PRISM,在此之前还从一些博客上了解了其他的MVVM框架,比如浅谈WPF中的 ...

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

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

  7. 从PRISM开始学WPF(八)导航Navigation-更新至Prism7.1

    原文:从PRISM开始学WPF(八)导航Navigation-更新至Prism7.1 0x6Navigation [7.1updated] Navigation 在wpf中并没有变化 Basic Na ...

  8. 从PRISM开始学WPF(番外)共享上下文 RegionContext?

    原文:从PRISM开始学WPF(番外)共享上下文 RegionContext? RegionContext共享上下文 There are a lot of scenarios where you mi ...

  9. 从PRISM开始学WPF(八)导航Navigation?

    原文:从PRISM开始学WPF(八)导航Navigation? 0x6Navigation Basic Navigation Prism中的Navigation提供了一种类似导航的功能,他可以根据用户 ...

随机推荐

  1. Android MediaScanner使用简单介绍

    1. 运行扫描 仅仅有系统开机的时候才会运行MediaScanner,其他情景下须要手动运行扫描(拍摄,下载等). 手动运行扫描的方法是发送MediaScanner广播: 1.1 扫描指定文件: In ...

  2. 《写给大忙人看的Java SE 8》——Java8新特性总结

    阅读目录 接口中的默认方法和静态方法 函数式接口和Lambda表达式 Stream API 新的日期和时间 API 杂项改进 参考资料 回到顶部 接口中的默认方法和静态方法 先考虑一个问题,如何向Ja ...

  3. APPCAN学习笔记002---app高速开发AppCan.cn平台特色

    技术qq交流群:JavaDream:251572072 1.多窗体机制   常见应用仅仅支持单一窗体 2.原生UI与交互支持   大量原生UI与交互支持(如Action Sheet等) 3.第三方开放 ...

  4. Expression Blend 的点滴(4)--创建类似iPhone屏幕锁控件(上)

    原文:Expression Blend 的点滴(4)--创建类似iPhone屏幕锁控件(上) 本篇文章,最终效果图:  当然,不只是一个UI而已,如果只是一张图片,那专业的设计师能做出更出色的效果.在 ...

  5. 【t054】糟糕的网络

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 前几天sqybi 还在高高兴兴的用BOINC 完成着一个又一个的任务呢,但现在sqybi 突然变得闷闷 ...

  6. lucene 7.x 排序

    一.创建索引 @Test public void indexCreate() throws IOException { //创建分词器 Analyzer analyzer = new Standard ...

  7. JAVA SE回顾及思考(1)——面向对象的特点

    学习Java已经三年了,现在开始做Android开发,虽说还在用Java语言但本人现在才真真的意识到无论学什么基础才是最重要的,可能一些刚接触Java或者Android的朋友现在还体会不到基础的重要性 ...

  8. Dictionary实现(收藏的)

    源文献:https://www.cnblogs.com/InCerry/p/10325290.html 对于C#中的Dictionary类相信大家都不陌生,这是一个Collection(集合)类型,可 ...

  9. WPF 获得触摸精度和触摸点

    原文:WPF 获得触摸精度和触摸点 本文主要告诉大家如何获得所有的触摸设备的触摸精度和触摸点数. 需要通过反射的方法才可以拿到触摸的精度. 使用 Tablet.TabletDevices 可以获得所有 ...

  10. 使用readLine()方法遇到的坑

    程序很简单,客户段从控制台读取用户输入,然后发送至服务器端,主要代码如下 服务端代码: 客户端代码: 结果运行的时候,当开启服务端和客户端后,在客户端的控制台 键盘输入 内容,服务端却没有显示内容 原 ...