1. 程式人生 > 其它 >六、從GitHub瀏覽Prism示例程式碼的方式入門WPF下的Prism之MVVM中的FilteringEvents

六、從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