zoukankan      html  css  js  c++  java
  • 从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator-更新至Prism7.1

    事件聚合器EventAggregator

    [7.1updated]除了app部分,没有任何变化

    • 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 委托

  • 相关阅读:
    pytesseract.pytesseract.TesseractNotFoundError: tesseract is not installed or it's not in your path
    图片验证码识别:ModuleNotFoundError: No module named 'ShowapiRequest'
    升级 pip 超时解决方案
    Python 技术篇-pip版本查看和升级
    Python 使用 paho-mqtt
    what's the psutil模块
    web.py小记
    Docker 安装 Redis
    树莓派小用手册(安装系统,配置图形界面,连接WiFi,调用摄像头,安装ffmpeg)
    Navicat 破解版链接
  • 原文地址:https://www.cnblogs.com/hicolin/p/8707903.html
Copyright © 2011-2022 走看看