• 菲佣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>

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

  • 相关阅读:
    SQL存储过程基础(从基础开始学,加油!)
    SQL语句经典大全
    SQL SQL语句的增删改查
    web app iphone4 iphone5 iphone6 响应式布局 适配代码
    DOM和 jquery 基础
    HTML 和CSS 语言
    python的目标
    老男孩学习DAY11-1 进程、进程池、协程
    老男孩python DAY10 soket 编程
    老男孩全栈PYTHON -DAY8-面向妹子(对象)编程
  • 原文地址:https://www.cnblogs.com/qiurideyun/p/2937638.html
Copyright © 2020-2023  润新知