Prism V2之旅(6)
這篇來講事件.事件主要用來互動.
監聽事件
我訂閱了一些blog的rss,如果我訂閱的blog釋出了新的文章的話,系統(就是抓蝦)就會幫我抓取新的rss資訊
很好理解,一方訂閱(Subscribe),一方釋出(Publish).
prism的事件
prism的抽象類EventBase實現了事件的訂閱和釋出的操作.CompositePresentationEvent類繼承自EventBase做了進一步封裝,其是一個泛型類,我們可以通過CompositePresentationEvent來傳遞一個引數.
下面是一個簡單的示例,記得先呼叫Subscribe方法訂閱事件,然後呼叫Publish方法來發布,同時也可以呼叫Unsubscribe方法來取消訂閱
private void SubscribeAndRaiseEvent() { CompositePresentationEvent<string> compositePresentationEvent = new CompositePresentationEvent<string>(); var action = new Action<string>((str) => { System.Windows.MessageBox.Show(str); }); compositePresentationEvent.Subscribe(action); compositePresentationEvent.Publish("hello"); compositePresentationEvent.Unsubscribe(action); compositePresentationEvent.Publish("hello"); }
多重訂閱,可以訂閱多個事件
private void MultipleSubscribersAndRaiseCustomEvent() { CompositePresentationEvent<string> compositePresentationEvent = new CompositePresentationEvent<string>(); var actionOne = new Action<string>((str) => { System.Windows.MessageBox.Show(str); }); var actionTwo = new Action<string>((str) => { System.Windows.MessageBox.Show(str); }); compositePresentationEvent.Subscribe(actionOne); compositePresentationEvent.Publish("hello"); compositePresentationEvent.Unsubscribe(actionTwo); compositePresentationEvent.Publish("world"); }
事件聚合模組互動
上面程式碼為示例,效果與.net內建的事件相似,只是做法不同而已,這樣的話沒多大意義,如果不同模組之間需要互動,那麼事件就起作用了.
所以就需要一個容器來儲存事件的狀態,prism的IEventAggregator介面便是這樣設計的
當事件被訂閱的事件,IEventAggregator的GetEvent方法,該方法是一個泛型方法,傳入的引數必須繼承自EventBase,
該方法會先例項化這個類,所以我們不可以出現這樣的程式碼
private void CustomEventWithEventAggregator() { eventAggregator.GetEvent<CompositePresentationEvent<string>>(); }
正確的做法是從CompositePresentationEvent派生一個類,如
private void CustomEventWithEventAggregator() { var action = new Action<string>((str) => { System.Windows.MessageBox.Show(str); }); eventAggregator.GetEvent<CustomEvent>().Subscribe(action); eventAggregator.GetEvent<CustomEvent>().Publish("hello"); } public class CustomEvent : CompositePresentationEvent<string> { }
以上程式碼為演示,你只需要明確定義Event的型別,就可以在不同模組互動.兩個模組之間就不要相互引用,降低了耦合度.
事件的回撥方式
當事件回撥時(即事件被觸發時),有三種方式.
1.同步執行緒 該怎麼處理就怎麼處理,預設情況下是以這種方式來處理的
2.在UI執行緒上觸發,即呼叫了wpf Dispatcher的BeginInvoke方法
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, method, arg);
3.在後臺執行緒上非同步呼叫,即通過BackgroundWorker類來非同步操作
public override void InvokeAction(Action<TPayload> action, TPayload argument) { BackgroundWorker worker = new BackgroundWorker(); worker.DoWork += ((sender, e) => action((TPayload)e.Argument)); //handle worker.RunWorkerCompleted and log exceptions? worker.RunWorkerAsync(argument); }
這三種方式是由ThreadOption列舉來設定的
這便是CompositePresentationEvent類擴充套件的功能之一,如下程式碼
public virtual SubscriptionToken Subscribe(Action<TPayload> action, ThreadOption threadOption, bool keepSubscriberReferenceAlive, Predicate<TPayload> filter) { IDelegateReference actionReference = new DelegateReference(action, keepSubscriberReferenceAlive); IDelegateReference filterReference; if (filter != null) { filterReference = new DelegateReference(filter, keepSubscriberReferenceAlive); } else { filterReference = new DelegateReference(new Predicate<TPayload>(delegate { return true; }), true); } EventSubscription<TPayload> subscription; switch (threadOption) { case ThreadOption.PublisherThread: subscription = new EventSubscription<TPayload>(actionReference, filterReference); break; case ThreadOption.BackgroundThread: subscription = new BackgroundEventSubscription<TPayload>(actionReference, filterReference); break; case ThreadOption.UIThread: subscription = new DispatcherEventSubscription<TPayload>(actionReference, filterReference, UIDispatcher); break; default: subscription = new EventSubscription<TPayload>(actionReference, filterReference); break; } return base.InternalSubscribe(subscription); }
弱引用還是強引用?
通過上面的程式碼,我們看到該方法還有一個引數keepSubscriberReferenceAlive,預設值是false,就是弱引用了,如果你設定成強引用,記得在不需要事件的時候,取消事件的訂閱.
事件過濾
Subscribe方法最後一個方法是filter事件過濾器,
舉個例子我訂閱了某某技術牛人的rss,平時他都寫一些技術文章,可他也喜歡寫了一些與技術無關的文章,我不想看,並不是他釋出什麼內容我都接受的,我是要有所選擇的,我要把這些內容過濾掉.這個功能比較好.平時看報紙就沒這個功能:).
上面的解釋就是事件過濾器的功能.
事件在v2的改動不是很大,大家也可以參考這篇,有重複了,這篇就到這裡