MVFM框架----模块间最大化解耦之广播监听模式

   虽说大部分的逻辑交互可以通过数据绑定和命令绑定实现,但依然有些需求需要在逻辑模块中涉及到UI.比如说--提示。

   有些逻辑处理结果需要展示给用户看,展示的方式很多样。如,界面弹框,提示等等。由于展示都是临时性的,通过绑定展示的话并不是好的选择,那怎么办呢?我选择用广播监听的方式。

  大概原理是:逻辑处理完成后,广播一个特定的信号出去,信号中附加参数,接收到的模块自己选择处理方式。

  看下面的代码:

    public delegate void Handler(object sender, CommonEventArgs e);

    public static class EventDispatcher
    {
        #region Private
        private static Dictionary<string, Dictionary<string, Handler>> TypeHandlers = new Dictionary<string, Dictionary<string, Handler>>();
        #endregion

        #region FireEvent Function
        public static void FireEvent(object Sender, string KeyType, string Key, CommonEventArgs e)
        {
            if (!TypeHandlers.ContainsKey(KeyType))
                return;

            Dictionary<string, Handler> Handlers = TypeHandlers[KeyType];

            if (Handlers != null && Handlers.ContainsKey(Key))
            {
                Handlers[Key](Sender, e);
            }
        }

        public static void FireEvent(object sender, string key, CommonEventArgs e)
        {
            FireEvent(sender, BaseEventKeys.DefaultKeyType, key, e);
        }

        public static void FireEvent(string key, CommonEventArgs e)
        {
            FireEvent(null, BaseEventKeys.DefaultKeyType, key, e);
        }

        #endregion

        #region Register Function
        public static void RegisterHandler(string KeyType, string Key, Handler Func)
        {
            if (string.IsNullOrEmpty(Key) || Func==null)
            {
                throw new Exception("Invalid Key or Function");
            }

            Dictionary<string, Handler> Handers = GetKeyTypeList(KeyType);

            if (Handers.ContainsKey(Key))
            {
                Handers[Key] += Func;
            }
            else
            {
                Handers.Add(Key, Func);
            }
        }


        public static void RegisterHandler(string key, Handler func)
        {
            RegisterHandler(BaseEventKeys.DefaultKeyType, key, func);
        }

        #endregion

        #region UnRegister Function
       
        public static void UnRegisterHandler(string key)
        {
            UnRegisterHandler(BaseEventKeys.DefaultKeyType,key,null);
        }

        public static void UnRegisterHandler(string KeyType, string Key, Handler Func)
        {
            Dictionary<string, Handler> Handlers = GetKeyTypeList(KeyType);

            if (Handlers == null || !Handlers.ContainsKey(Key))
                return;

            if (Func == null)
                Handlers.Remove(Key);
            else
            {
                Handlers[Key] -= Func;

               if (Handlers[Key]==null)
                   Handlers.Remove(Key);
            }

        }
        #endregion

        #region Private Function
        private static Dictionary<string, Handler> GetKeyTypeList(string KeyType)
        {
            if (string.IsNullOrEmpty(KeyType))
            {
                throw new Exception("Invalid KeyType");
            }

            if (!TypeHandlers.ContainsKey(KeyType))
            {
                Dictionary<string, Handler> EventHandlers = new Dictionary<string, Handler>();
                TypeHandlers.Add(KeyType, EventHandlers);
                return EventHandlers;
            }

            return TypeHandlers[KeyType];

        }

        #endregion
    }
   EventDispatcher 的主要作用是处理信号注册和信号广播,这是一个静态类,不需要实例化既可以直接使用,可用于任何模块之间的交互。

   RegisterHandler用于监听信号,KeyType是信号域,Key是信号域下的子信号,Func是处理此信号的函数。由于信号可能很多,而且有些信号是同一种类别,所以我加上了信号域的概念。注册的时候不填写信号域就会使用默认的信号域。

  所有的信号都存储在TypeHandlers中,这是个哈希表,所以不用担心信号过多时会出现性能问题。

  FireEvent用于广播信号,Sender为发送者,KeyType为信号域,Key是信号e则是信号所附带的参数。

  e的类型为CommonEventArgs,以下为它的代码:

public class CommonEventArgs : EventArgs
    {
        private Dictionary<string, object> args = new Dictionary<string, object>();

        public Handler Handler;

        public CommonEventArgs()
        {        
        }

        public CommonEventArgs(string argName, object argValue)
        {
            args.Add(argName, argValue);
        }

        public void Add(string argName, object argValue)
        {
            args.Add(argName, argValue);
        }

        public T Get<T>(string argName)
        {
            return args.ContainsKey(argName) ? (T)args[argName] : default(T);
        }

        public object Get(string argName)
        {
            return args.ContainsKey(argName) ? args[argName] : default(object);
        }

        public T Get<T>(string argName,T defaultValue)
        {
            return args.ContainsKey(argName) ? (T)args[argName] : defaultValue;
        }
    }
  这个类中将附带信号处理所需的所有数据,数据存储在args中,这依然是个哈希表。通过事先约定好的键值进行存储。另外还有个Handler参数,这个参数可以用于回掉。当摸个信号接收到并处理完成后,可以用Handler参数反馈给发送着。

  下面看一下简单的使用方法,首先定义信号域和子信号:

public class BaseEventKeys
	{
        
        /// <summary>
        /// 数据模板
        /// </summary>
        public static string Protocol = "Protocol";

        /// <summary>
        /// 默认类型
        /// </summary>
        public static string DefaultKeyType = "Default";
    }
  信号域和子信号都是string类型,DefaultKeyType为默认信号域,Protocol则为默认的子信号。

  假定有以下逻辑需要实现:某个数据列表需要从服务器获取数据源,当异步获取数据成功时,在当前界面想用户进行提示“获取数据成功!”。

  首先在BaseEventKeys中添加信号GetDataSucced:

  public static string GetDataSucced= "Succed";
  然后在当前页面注册此信号:

    public sealed partial class GroupedItemsPage : MvfmText.Common.LayoutAwarePage
    {
        public GroupedItemsPage()
        {
            this.InitializeComponent();    
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
            EventDispatcher.RegisterHandler(BaseEventKeys.GetDataSucced, GetDataSucced);
        }


        void GetDataSucced(object sender, CommonEventArgs e)
        {
            string msg = e.Get<string>(BaseEventKeys.Protocol);

            if (!string.IsNullOrEmpty(msg))
                MessageBox.Show(msg);
        }
    }
   最后当需要提醒用户只需调用以下代码即可:
 EventDispatcher.FireEvent(BaseEventKeys.GetDataSucced, new CommonEventArgs(BaseEventKeys.Protocol, "获取数据成功!"))
  是不是很简单!使用这种模式传递信息的好处在于模块之间最大化的解耦,同时又完成了模块之间的通信。这种通信方式符合设计模式四原则中的迪米特法则。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章