菲佣WPF——7(再造轮子-事件的订阅和发布)

关于事件的订阅和发布,相信网上已经有很多版本了。基本的原理就是先订阅事件,将订阅的事件保存到特定的容器中,接着,当发布事件的时候,直接调用的保存的事件。

.NET不是已经提供了Event,为什么还要做事件的订阅和发布。

我个人的理解是高度封装自己的事件,这样代码简洁美观,并且易于维护和扩展。

我采用了静态的容器来保存订阅的事件,这样可以跨组建或项目的程序集。

首先我们要定义我们自己的Event事件

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace FYFrameWork.Event
{
    public class FYEventBase<T>:FYEvent
    {
        #region << Field >>
        EventDispathcher eventDispathcher = new EventDispathcher();
        #endregion

        #region << Method >>
        /// <summary>
        /// subscribe the event
        /// </summary>
        /// <param name="action">subscribe's delegate</param>
        /// <param name="callMode">subscribe's call function mode</param>
        public virtual void Subscribe(Action<T> action) 
        {
            eventDispathcher.AddEvent(new FYWeakReference(action));
        }

        /// <summary>
        /// publish the event
        /// </summary>
        /// <param name="objs">publish's function's parameters</param>
        public virtual  void Publish(CallMode callMode,object objs) 
        {
            if (callMode == CallMode.SynCall)
            {
                ///syn call list of delegate
                eventDispathcher.GetEvent().ForEach(p =>
                                                   {
                                                       Application.Current.Dispatcher.Invoke(((Action<T>)(p.GetAction())), (T)objs);
                                                   });
            }
            else
            {
                ///asyn call list of delegate
                eventDispathcher.GetEvent().ForEach(p =>
                                                   {
                                                        Application.Current.Dispatcher.BeginInvoke(((Action<T>)(p.GetAction())),(T)objs);
                                                   });
            }
        }
        #endregion
    }
}

我们自定义的EventBase  只有两个方法 Subscribe和Publish

Subscribe用来订阅事件(我们这里泛指 无返回值的函数,有返回值的函数我会继续在下个版本加入)

至于FYEvent只是个空的抽象类,就是为了实现EventBase<T>的泛型,有好的办法,大家通知我。

这里我们会看到EventDispathcher类,主要是个List用来村粗Action<T>(无返回函数的委托)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FYFrameWork.Event
{
    public class EventDispathcher
    {
        #region << Field >>
        /// <summary>
        /// save event dispathcher list
        /// </summary>
        private  List<FYWeakReference> dispathcherCache = new List<FYWeakReference>();
    
        #endregion


        #region << Method >>
        /// <summary>
        /// add event
        /// </summary>
        /// <param name="weakReference">event delegate object</param>
        public void AddEvent(FYWeakReference weakReference) 
        {
            if (weakReference == null)
                throw new Exception("weakReference is null");

            var isExist = dispathcherCache.Any((p) => p == weakReference);

            if (!isExist)
            {
                dispathcherCache.Add(weakReference);
            }
        }

        /// <summary>
        /// remove event
        /// </summary>
        /// <param name="weakReference">event delegate object</param>
        public void RemoveEvent(FYWeakReference weakReference) 
        {
            if (weakReference != null)
            {
                var isExist = dispathcherCache.Any((p) => p == weakReference);

                if (isExist)
                    dispathcherCache.Remove(weakReference);
            }
        }

        /// <summary>
        /// get event
        /// </summary>
        /// <returns></returns>
        public List<FYWeakReference> GetEvent()
        {
            return dispathcherCache;
        }
        #endregion
    }
}

AddEvent就是用来添加Action<T>
在这里又会有FYWeakReference类,就是就是Action<T> 的WeakReference对象。

为什么用WeakReference,用弱引用是尽量的当事件太多时,对于内存的压力。

WeakReference的代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace FYFrameWork.Event
{
    public class FYWeakReference : IFYWeakReference
    {
        #region << Field >>
        private readonly MethodInfo methodInfo;
        private readonly WeakReference weakReference;
        private readonly Type actionType;
        private readonly Delegate action;
        #endregion

        #region << Constructor >>
        public FYWeakReference(Delegate action):this(action,false){}
        public FYWeakReference(Delegate action, bool isKeepAlive)
        {
            if (action == null)
                throw new Exception("delegate is null");

            if (isKeepAlive)
            { 
                this.action = action;
            }
            else
            {
                actionType = action.GetType();
                weakReference = new WeakReference(action.Target);
                methodInfo = action.Method;
            }
        }
        #endregion

        #region << Method >>
        /// <summary>
        /// get delegate
        /// </summary>
        /// <returns>delegate</returns>
        public Delegate GetAction()
        {
            if (methodInfo.IsStatic)
            {
                return Delegate.CreateDelegate(actionType, null, methodInfo);
            }

            object obj = weakReference.Target;
            if (obj != null)
                return Delegate.CreateDelegate(actionType, obj, methodInfo);

            return null;
        }
        #endregion
    }
}

接着就是我们EventManager.

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FYFrameWork.Event
{
    public interface IFYEventManager
    {
        /// <summary>
        /// get event
        /// </summary>
        /// <typeparam name="T">event's type</typeparam>
        /// <returns>event object</returns>
        T GetEvent<T>() where T : FYEvent, new();
    }
}
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FYFrameWork.Event
{
    [Export]
    public class FYEventManager:IFYEventManager
    {
        #region << Field >>
        private static Dictionary<Type, FYEvent> eventCache = new Dictionary<Type, FYEvent>();
        #endregion

        #region << Method >>
        /// <summary>
        /// get the event
        /// </summary>
        /// <typeparam name="T">event type</typeparam>
        /// <returns></returns>
        public T GetEvent<T>() where T : FYEvent, new()
        {
            if (eventCache.ContainsKey(typeof(T)))
                return (T)eventCache[typeof(T)];
            else
            {
                T tmpEvent = new T();
                eventCache.Add(typeof(T), tmpEvent);
                return tmpEvent;
            }
        }
        #endregion
    }
}

这EventManager我用字典来存储我们自定义的事件。
GetEvent<T> 泛型来取得对应的事件对象,来进行订阅和发布。

整个订阅和发布,其实就是先存储Event,再调用Event对应的Action<T>

目前这个事件小框架,还不太完善,先发出来,大家讨论下,希望你们也可以发布自己的事件订阅和发布框架。

posted @ 2013-02-28 19:52  qiurideyun  阅读(1597)  评论(0编辑  收藏  举报