1. 程式人生 > >Prism V2之旅(6)

Prism V2之旅(6)

這篇來講事件.事件主要用來互動.

監聽事件

 

訂閱了一些blog的rss,如果我訂閱的blog釋出了新的文章的話,系統(就是抓蝦)就會幫我抓取新的rss資訊

image

很好理解,一方訂閱(Subscribe),一方釋出(Publish).

prism的事件

 

prism的抽象類EventBase實現了事件的訂閱和釋出的操作.CompositePresentationEvent類繼承自EventBase做了進一步封裝,其是一個泛型類,我們可以通過CompositePresentationEvent來傳遞一個引數.

image

 

下面是一個簡單的示例,記得先呼叫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列舉來設定的

image

這便是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的改動不是很大,大家也可以參考這篇,有重複了,這篇就到這裡