Prism V2之旅(6)
2009-01-13 15:14 Clingingboy 阅读(7238) 评论(4) 编辑 收藏 举报这篇来讲事件.事件主要用来交互.
监听事件
我订阅了一些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的改动不是很大,大家也可以参考这篇,有重复了,这篇就到这里