这篇来讲事件.事件主要用来交互.
监听事件
我订阅了一些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的改动不是很大,大家也可以参考这篇,有重复了,这篇就到这里