zoukankan      html  css  js  c++  java
  • 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的改动不是很大,大家也可以参考这篇,有重复了,这篇就到这里

  • 相关阅读:
    eureka_feign学习_1
    九度 题目1183:守形数----------------我用的方法自创
    题目1179:阶乘-------------阶乘不用long long int 就不能AC
    题目1177:查找---------------字符串的函数问题
    题目1170:找最小数-------------------------------找最小值,中间值应该初始化为最大值
    题目1169:比较奇偶数个数-----------------------------这个世界不是奇数就是偶数l
    题目1075:斐波那契数列
    题目1070:今年的第几天?---------关键是闰年的判断
    题目1068:球的半径和体积----------------------------arccos(-1)要用c语言中的acos(-1)代替
    题目1067:n的阶乘--------long long int
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/prism_part6.html
Copyright © 2011-2022 走看看