• 六、从GitHub浏览Prism示例代码的方式入门WPF下的Prism之MVVM中的FilteringEvents


    上一篇分析了EventAggregator,我们直到了如何使用EventAggregatir,因为示例比较简单,所以我们没有写DEMO,结合EventAggregator和15示例,FilteringEvents来过滤事件。我们就可以写一个相对复杂一点的DEMO,用于理解EventAggregator和FilterEvent。

    从15示例继续学习Prism下的MVVM思想

    分析15示例FilterEvent,学习在EventAggretator中如何使用FilterEvent。

    1、引用关系

    UsingEventAggregator.Core工程引用了Prism.Core;

    ModuleA工程引用了UsingEventAggregator.Core、引用了Prism.Wpf;

    ModuleB工程引用了UsingEventAggregator.Core、引用了Prism.Wpf;

    UsingEventAggregator工程引用了ModuleA、ModuleB、UsingEventAggregator.Code、Prism.Unity。

    2、分析UsingEventAggregator.Core工程

    UsingEventAggregator.Core中引用了Prism.Core;

    2.1、MessageSentEvent.cs

    在MessageSentEvent.cs中创建了MessageSentEvent并继承自PubSubEvent。这个PubSubEvent我们上一篇已经了解过了,他继承自Prism.Events命名空间下的EventBase,主要是用Publish发送内容,接收方使用Subscribe订阅事件。

    3、分析ModuleA工程

    ModuleA中引用了Prism.Wpf、引用了UsingEventAggregator.Core;

    3.1、ModuleAModule.cs

    ModuleAModule继承自Prism.Modularity.IModule

    在ModuleAModule中的OnInitialized()方法中获取到了RegionManager对象,然后关联显示区域LeftRegion和视图MessageView。

    3.2、Views下的MessageView.xaml

    在MessageView.xaml 中添加命名空间prism="http://prismlibrary.com/",添加prism.ViewModelLocator.AutoWireViewModel=true用于自和ViewModel关联。

    xaml中包含一个用于输入的文本框TextBox 输入内容绑定到了Message属性,Button是绑定到了一个SendMessageCommand命令,这2个对象都是ViewModel下的。cs文件中无额外代码;

    3.3、ViewModel下的MessageViewModel.cs

    MessageViewModel继承自Prism.Mvvm.BindableBase,创建了一个属性Message,一个DelegateCommand类型的SendMessageCommand命令,创建字段IEventAggregator类型的_ea,在构造函数MessageViewModel()中初始化ea和SendMessageCommand,使他绑定到SendMessage()方法。

    SendMessage()方法使用ea字段获取MessageSendEvent事件,然后使用Publish的方法触发事件,然后再订阅该事件的地方就可以接收到消息了。

    4、分析ModuleB工程

    ModuleB引用了Prism.Wpf、UsingEventAggregator.Core;

    4.1、ModuleBModule.cs

    ModuleBModule继承自Prism.Modularity.IModule,再OnInitialized()方法中获取RegionManager对象,关联RgihtRegion显示区域和MessageList视图。

    4.2、Views下的MessageList.xaml

    MessageList.xaml 添加命名控件prism="http://prismlibrary.com/",添加prism:ViewModelLocator.AutoWireViewModel=true用于关联ViewModel。

    添加了一个显示控件ListBox ItemsSource绑定位Messages对象,cs文件下无额外代码

    4.3、ViewModels下的MessageListViewModel.cs

    MessageListViewModel继承自Prism.Mvvm.BindableBase,创建属性Messages,创建字段_ea并在构造函数中初始化,构造函数中实例化Messages,同时使用ea订阅MessageSentEvent事件,重点来了,这一篇主要的内容就是这一段代码,我们再Subscribe上使用F12跳转过去。

    IEventAggregator _ea;
    public MessageListViewModel(IEventAggregator ea)
            {
                _ea = ea;
                Messages = new ObservableCollection<string>();
    
                _ea.GetEvent<MessageSentEvent>().Subscribe(MessageReceived, ThreadOption.PublisherThread, false, (filter) => filter.Contains("Brian"));
            }
    
    
      //
            // 摘要:
            //     Subscribes a delegate to an event.
            //     订阅事件的委托。
            // 参数:
            //   action:
            //     The delegate that gets executed when the event is published.
            //     发布事件时执行的委托。
            //
            //   threadOption:
            //     Specifies on which thread to receive the delegate callback.
            //     指定在哪个线程上接收委托回调。
            //
            //   keepSubscriberReferenceAlive:   //保持订阅服务器引用处于活动状态
            //     When true, the Prism.Events.PubSubEvent`1 keeps a reference to the subscriber
            //     so it does not get garbage collected.
            //     如果为true,则Prism.Events.PubSubEvent`1保留对订阅服务器的引用,因此不会对其进行垃圾收集。
            //
            //
            //   filter:
            //     Filter to evaluate if the subscriber should receive the event.
    		//     筛选以评估订阅服务器是否应接收事件。
            //
            // 返回结果:
            //     A Prism.Events.SubscriptionToken that uniquely identifies the added subscription.
    		//     唯一标识添加订阅的Prism.Events.SubscriptionToken。
            //
            // 言论:
            //     If keepSubscriberReferenceAlive is set to false, Prism.Events.PubSubEvent`1 will
            //     maintain a System.WeakReference to the Target of the supplied action delegate.
            //     If not using a WeakReference (keepSubscriberReferenceAlive is true), the user
            //     must explicitly call Unsubscribe for the event when disposing the subscriber
            //     in order to avoid memory leaks or unexpected behavior. The PubSubEvent collection
            //     is thread-safe.
    		//
    		//     如果keepSubscriberReferenceAlive设置为false,
    		//     则Prism.Events.PubSubEvent`1将维护对所提供操作委托的目标的System.WeakReference。
    		//     如果未使用WeakReference(keepSubscriberReferenceAlive为true),
    		//     则用户在处理订阅服务器时必须显式调用Unsubscribe以避免内存泄漏或意外行为。PubSubEvent集合是线程安全的。 
    		//
            public virtual SubscriptionToken Subscribe(Action<TPayload> action, ThreadOption threadOption, bool keepSubscriberReferenceAlive, Predicate<TPayload> filter);
    

    我们详细看一下这里的说明:

    第一个参数Action action是传入一个action类型的参数,用于事件触发后执行的委托;

    第二个参数是枚举类型的ThreadOption,有三个参数PublisherThread,UIThread,BackgroundThread。看名称我们就能理解,设置代码在什么线程上工作;

    第三个参数是Bool类型的,看说明如果设置为true则该订阅不会对其进行垃圾回收;

    最后一个参数就是我们的过滤器,用于筛选是否符合我们要求的Event;

    我们在看这段代码

       public MessageListViewModel(IEventAggregator ea)
            {
                _ea = ea;
                Messages = new ObservableCollection<string>();
    
                _ea.GetEvent<MessageSentEvent>().Subscribe(MessageReceived, ThreadOption.PublisherThread, false, (filter) => filter.Contains("Brian"));
            }
    
            private void MessageReceived(string message)
            { 
                Messages.Add(message);
            }
    

    在使用Subscribe的时候,第一个参数传入了MessageReceived作为回调函数,ThreadOption设置为PublisherThread工作线程,false代表该订阅需要GC进行垃圾回收,子厚一个参数是一个匿名函数,因为MessageSentEvent传入的是string类型的参数,所以filter是这个string类型的形参,filter.contains("Brian")是在实际调用中,判断filter中是否包含Brian字符串,结合ModuleA就是判断用户输入的内容中是否包含Brian,如果包含则触发MessageReceived函数。

    5、分析主工程UsingEventAggregator

    UsingEventAggregator工程引用了Prism.Unity,引用了ModuleA、ModuleB、UsingEventAggregator.Core;

    5.1、App.xaml

    添加prism="http://prismlibrary.com/"命名空间

    修改Application为prism:PrismApplication;

    移除StartUpUri属性

    5.2、App.cs

    修改App继承自PrismApplication

    重新CreateShell()设置启动页为MainWindow

    重写ConfigureModuleCatalog()用于加载ModuleA下的ModuleAModule和ModuleB下的ModuleBModule

    5.3、Views下的MainWindow.xaml

    添加命名空间prism="http://prismlibrary.com/"

    设置prism:ViewModelLocator.AutoWireViewModel=true关联ViewModel

    通过Grid把当前Window平均左右布局分成2份,在Grid中使用ContentControl左右各放置一个,并设置附加依赖项属性prism:ReegionManager.RegionName为LeftRegion和RightRegion,cs代码中无新增内容

    5.4、ViewModels下的MainWindowViewModel.cs

    MainWindowViewModel继承自Prism.Mvvm.BindableBase;

    设置了属性Title并初始化,用于显示Main中的Title;

    总结示例:我们分析了整个工程的代码,通用部分的代码通过这么多例子的讲解我们基本上都了解了,这里就不说了,就说这篇最重要的部分,UsingEventAggregator.Core下的MessageSentEvent.cs继承了PubSubEvent。参数为String。

    ModuleA和ModuleB无直接关联关系,ModuleA通过在ViewModel中接收IEventAggregator,来关联Command和MessageSentEvent的Publish.用于发送事件,

    ModuleB在ViewModel中接收IEventAggregator,通过订阅Subscribe时传入的匿名函数的参数filter来过滤包含Brian的消息才会触发前面的回调。

    就完成了EventAggregator相关的订阅、触发、过滤功能。

    这篇也比较简单, 先不写DEMO了,继续往后看。

    我创建了一个C#相关的交流群。用于分享学习资料和讨论问题。欢迎有兴趣的小伙伴:QQ群:542633085

  • 相关阅读:
    JS Dom_API
    JS 动态表格(添加、删除行)
    将本地网页上传到 apache2 及 github 的步骤
    软件工程之美 第一周
    树莓派安装芯片驱动并测试
    Visoul Studio 2019 远程调试 中文乱码
    Visoul Studio 2019 远程调试 RaspberryPi C 项目
    课设提纲
    PHP PDO 一 : 常用方法
    设置子域名及申请其证书
  • 原文地址:https://www.cnblogs.com/duwenlong/p/15167896.html
Copyright © 2020-2023  润新知