UIFramework之事件系统实现

时间:2022-04-26 23:22:47

UIFramework之事件系统实现

在Unity开发中,自定义消息系统经常会被用到,事件系统的实现主要是基于C#委托来完成的。下面介绍的两种实现,一种是利用C#自带的Action委托来实现;第二种是通过自定义一个信息类来作为传递信息的载体,再通过自定义委托来实现的。

实现一:

首先在MessageSystem.cs中实现事件系统的基本功能:

[csharp]  view plain  copy  print ?
  1. /* 
  2. * Name: MessageSystem.cs 
  3. * Function: N/A  
  4.  
  5. * Ver     变更日期               负责人                            变更内容 
  6. * ────────────────────────────────────────────────────────────────────── 
  7. * V1.0.0  $time$    http://blog.csdn.net/husheng0      
  8.  
  9. * Copyright (c). All rights reserved. 
  10. */  
  11.   
  12. using System;  
  13. using System.Collections.Generic;  
  14. using UnityEngine;  
  15.   
  16. public static class MessageSystem<TKey> where TKey : struct  
  17. {  
  18.     //MessageKey对应的注册的委托  
  19.     private static Dictionary<TKey, List<Delegate>> RegisterMessageDic   
  20.         = new Dictionary<TKey, List<Delegate>>();  
  21.     //移出对应的委托  
  22.     public static void UnRegisterDelegate(TKey MessageKey)  
  23.     {  
  24.         RegisterMessageDic.Remove(MessageKey);  
  25.     }  
  26.     //清空事件系统已注册事件  
  27.     public static void CleanEvents()  
  28.     {  
  29.         RegisterMessageDic.Clear();  
  30.   
  31.     }  
  32.     //能不能注册该委托  
  33.     private static bool IsCanRegister(TKey MessageKey, Delegate registerDelegate)  
  34.     {  
  35.         List<Delegate> registerDelegateList = null;  
  36.         if (RegisterMessageDic.TryGetValue(MessageKey, out registerDelegateList))  
  37.         {  
  38.             if (null == registerDelegateList || registerDelegateList.Count == 0)   
  39.                 return true;  
  40.             foreach (Delegate dele in registerDelegateList)  
  41.             {  
  42.                 if (dele == registerDelegate) return false;  
  43.             }  
  44.         }  
  45.         else  
  46.         {  
  47.             RegisterMessageDic[MessageKey] = new List<Delegate>();  
  48.         }  
  49.         return true;  
  50.     }  
  51.  
  52.     #region Action委托  
  53.     /// <summary>  
  54.     /// 注册无参Action委托  
  55.     /// </summary>  
  56.     /// <param name="MessageKey"></param>  
  57.     /// <param name="handler"></param>  
  58.     public static void AddListener(TKey MessageKey, Action handler)  
  59.     {  
  60.         if (IsCanRegister(MessageKey, handler))  
  61.         {  
  62.             RegisterMessageDic[MessageKey].Add(handler);  
  63.             Debug.Log("Register" + MessageKey.ToString() + "success");  
  64.         }  
  65.         else  
  66.         {  
  67.             Debug.LogError("Register" + MessageKey.ToString() + "failure");  
  68.         }  
  69.     }  
  70.     /// <summary>  
  71.     /// 移除无参Action委托  
  72.     /// </summary>  
  73.     /// <param name="MessageKey"></param>  
  74.     /// <param name="handler"></param>  
  75.     public static void RemoveListenerer(TKey MessageKey, Action handler)  
  76.     {  
  77.         if (!IsCanRegister(MessageKey, handler))  
  78.         {  
  79.             RegisterMessageDic[MessageKey].Remove(handler);  
  80.             Debug.Log("Remove" + MessageKey.ToString() + "success");  
  81.         }  
  82.         else  
  83.         {  
  84.             Debug.LogError("Remove" + MessageKey.ToString() + "failure");  
  85.         }  
  86.     }  
  87.     /// <summary>  
  88.     /// 广播无参Action委托  
  89.     /// </summary>  
  90.     /// <param name="MessageKey"></param>  
  91.     public static void Broadcast(TKey MessageKey)  
  92.     {  
  93.         List<Delegate> registerDelegateList;  
  94.         if (RegisterMessageDic.TryGetValue(MessageKey, out registerDelegateList))  
  95.         {  
  96.             Action callback;  
  97.             for (int i = 0; i < registerDelegateList.Count; ++i)  
  98.             {  
  99.                 try  
  100.                 {  
  101.                     callback = (registerDelegateList[i]) as Action;  
  102.                     if (callback != null)  
  103.                     {  
  104.                         callback();  
  105.                     }  
  106.                 }  
  107.                 catch (Exception exp)  
  108.                 {  
  109.                     Debug.LogException(exp);  
  110.                 }  
  111.             }  
  112.         }  
  113.     }  
  114.  
  115.     #endregion  
  116.  
  117.  
  118.     #region Action<T>委托  
  119.     /// <summary>  
  120.     /// 注册含一个参数的委托  
  121.     /// </summary>  
  122.     /// <typeparam name="T"></typeparam>  
  123.     /// <param name="MessageKey"></param>  
  124.     /// <param name="handler"></param>  
  125.     public static void AddListener<T>(TKey MessageKey, Action<T> handler)  
  126.     {  
  127.         if (IsCanRegister(MessageKey, handler))  
  128.         {  
  129.             RegisterMessageDic[MessageKey].Add(handler);  
  130.             Debug.Log("Register" + MessageKey.ToString() + "success");  
  131.         }  
  132.         else  
  133.         {  
  134.             Debug.LogError("Register" + MessageKey.ToString() + "failure");  
  135.         }  
  136.     }  
  137.     /// <summary>  
  138.     /// 移除含一个参数的Action委托  
  139.     /// </summary>  
  140.     /// <typeparam name="T"></typeparam>  
  141.     /// <param name="MessageKey"></param>  
  142.     /// <param name="handler"></param>  
  143.     public static void RemoveListenerer<T>(TKey MessageKey, Action<T> handler)  
  144.     {  
  145.         if (!IsCanRegister(MessageKey, handler))  
  146.         {  
  147.             RegisterMessageDic[MessageKey].Remove(handler);  
  148.             Debug.Log("Remove" + MessageKey.ToString() + "success");  
  149.         }  
  150.         else  
  151.         {  
  152.             Debug.LogError("Remove" + MessageKey.ToString() + "failure");  
  153.         }  
  154.     }  
  155.     /// <summary>  
  156.     /// 广播含一个参数的Action委托  
  157.     /// </summary>  
  158.     /// <typeparam name="T"></typeparam>  
  159.     /// <param name="MessageKey"></param>  
  160.     /// <param name="arg1"></param>  
  161.     public static void Broadcast<T>(TKey MessageKey, T arg1)  
  162.     {  
  163.         List<Delegate> registerDelegateList;  
  164.         if (RegisterMessageDic.TryGetValue(MessageKey, out registerDelegateList))  
  165.         {  
  166.             Action<T> callback;  
  167.             for (int i = 0; i < registerDelegateList.Count; ++i)  
  168.             {  
  169.                 try  
  170.                 {  
  171.                     callback = (registerDelegateList[i]) as Action<T>;  
  172.                     if (callback != null)  
  173.                     {  
  174.                         callback(arg1);  
  175.                     }  
  176.                 }  
  177.                 catch (Exception exp)  
  178.                 {  
  179.                     Debug.LogException(exp);  
  180.                 }  
  181.             }  
  182.         }  
  183.     }  
  184.  
  185.     #endregion  
  186.  
  187.  
  188.     #region Action<T1,T2>委托  
  189.     /// <summary>  
  190.     /// 注册含两个参数的Action委托  
  191.     /// </summary>  
  192.     /// <typeparam name="T1"></typeparam>  
  193.     /// <typeparam name="T2"></typeparam>  
  194.     /// <param name="MessageKey"></param>  
  195.     /// <param name="handler"></param>  
  196.     public static void AddListener<T1, T2>(TKey MessageKey, Action<T1, T2> handler)  
  197.     {  
  198.         if (IsCanRegister(MessageKey, handler))  
  199.         {  
  200.             RegisterMessageDic[MessageKey].Add(handler);  
  201.             Debug.Log("Register" + MessageKey.ToString() + "success");  
  202.         }  
  203.         else  
  204.         {  
  205.             Debug.LogError("Register" + MessageKey.ToString() + "failure");  
  206.         }  
  207.     }  
  208.     /// <summary>  
  209.     /// 移除含两个参数的Action委托  
  210.     /// </summary>  
  211.     /// <typeparam name="T1"></typeparam>  
  212.     /// <typeparam name="T2"></typeparam>  
  213.     /// <param name="MessageKey"></param>  
  214.     /// <param name="handler"></param>  
  215.     public static void RemoveListenerer<T1, T2>(TKey MessageKey, Action<T1, T2> handler)  
  216.     {  
  217.         if (!IsCanRegister(MessageKey, handler))  
  218.         {  
  219.             RegisterMessageDic[MessageKey].Remove(handler);  
  220.             Debug.Log("Remove" + MessageKey.ToString() + "success");  
  221.         }  
  222.         else  
  223.         {  
  224.             Debug.LogError("Remove" + MessageKey.ToString() + "failure");  
  225.         }  
  226.     }  
  227.     /// <summary>  
  228.     /// 广播含两个参数的Action委托  
  229.     /// </summary>  
  230.     /// <typeparam name="T1"></typeparam>  
  231.     /// <typeparam name="T2"></typeparam>  
  232.     /// <param name="MessageKey"></param>  
  233.     /// <param name="arg1"></param>  
  234.     /// <param name="arg2"></param>  
  235.     public static void Broadcast<T1, T2>(TKey MessageKey, T1 arg1, T2 arg2)  
  236.     {  
  237.         List<Delegate> registerDelegateList;  
  238.         if (RegisterMessageDic.TryGetValue(MessageKey, out registerDelegateList))  
  239.         {  
  240.             Action<T1, T2> callback;  
  241.             for (int i = 0; i < registerDelegateList.Count; ++i)  
  242.             {  
  243.                 try  
  244.                 {  
  245.                     callback = (registerDelegateList[i]) as Action<T1, T2>;  
  246.                     if (callback != null)  
  247.                     {  
  248.                         callback(arg1, arg2);  
  249.                     }  
  250.                 }  
  251.                 catch (Exception exp)  
  252.                 {  
  253.                     Debug.LogException(exp);  
  254.                 }  
  255.             }  
  256.         }  
  257.     }  
  258.  
  259.     #endregion  
  260. }  

下面使用两个脚本进行简单的测试:

[csharp]  view plain  copy  print ? UIFramework之事件系统实现 UIFramework之事件系统实现
  1. /// <summary>  
  2. /// 全局事件  
  3. /// </summary>  
  4. public enum MsgTest  
  5. {  
  6.     Test1,  
  7.     Test2,  
  8.     Test3  
  9. }  

[csharp]  view plain  copy  print ? UIFramework之事件系统实现 UIFramework之事件系统实现
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. public class MessageSystemTest : MonoBehaviour  
  5. {  
  6.     void OnGUI()  
  7.     {  
  8.         if (GUI.Button(new Rect(50, 50, 200, 30), "Register Action"))  
  9.             MessageSystem<MsgTest>.AddListener(MsgTest.Test1, Test1Func);  
  10.         if (GUI.Button(new Rect(50, 100, 200, 30), "Broadcast Action"))  
  11.             MessageSystem<MsgTest>.Broadcast(MsgTest.Test1);  
  12.         if (GUI.Button(new Rect(50, 150, 200, 30), "Remove Action"))  
  13.             MessageSystem<MsgTest>.RemoveListenerer(MsgTest.Test1, Test1Func);  
  14.         if (GUI.Button(new Rect(50, 200, 200, 30), "Register Action<T>"))  
  15.             MessageSystem<MsgTest>.AddListener<int>(MsgTest.Test2, Test2Func);  
  16.         if (GUI.Button(new Rect(50, 250, 200, 30), "Broadcast Action<T>"))  
  17.             MessageSystem<MsgTest>.Broadcast<int>(MsgTest.Test2,100);  
  18.         if (GUI.Button(new Rect(50, 300, 200, 30), "Remove Action<T>"))  
  19.             MessageSystem<MsgTest>.RemoveListenerer<int>(MsgTest.Test2, Test2Func);  
  20.         if (GUI.Button(new Rect(50, 350, 200, 30), "Register Action<T1,T2>"))  
  21.             MessageSystem<MsgTest>.AddListener<int,string>(MsgTest.Test3, Test3Func);  
  22.         if (GUI.Button(new Rect(50, 400, 200, 30), "Broadcast Action<T1,T2>"))  
  23.             MessageSystem<MsgTest>.Broadcast<int,string>(MsgTest.Test3,100,"test");  
  24.         if (GUI.Button(new Rect(50, 450, 200, 30), "Remove Action<T1,T2>"))  
  25.             MessageSystem<MsgTest>.RemoveListenerer<int,string>(MsgTest.Test3, Test3Func);  
  26.     }  
  27.     private void Test1Func()  
  28.     {  
  29.         Debug.LogError("--->Test1Func");  
  30.     }  
  31.   
  32.     private void Test2Func(int i)  
  33.     {  
  34.         Debug.LogError("--->Test1Func"+i.ToString());  
  35.     }  
  36.   
  37.     private void Test3Func(int i,string str)  
  38.     {  
  39.         Debug.LogError("--->Test1Func" + i.ToString()+"  "+str);  
  40.     }  
  41. }  

测试结果如下图所示:

UIFramework之事件系统实现

UIFramework之事件系统实现


实现二:

第二种是实现方式与第一种实现方式其实是大同小异:

[csharp]  view plain  copy  print ? UIFramework之事件系统实现 UIFramework之事件系统实现
  1. using System;  
  2. using System.Collections.Generic;  
  3. using UnityEngine;  
  4.   
  5. public static class MessageCenter  
  6. {  
  7.   
  8.     public delegate void MessageEvent(Message message);  
  9.   
  10.     private static Dictionary<string, List<MessageEvent>> MessageEventsDic =  
  11.         new Dictionary<string, List<MessageEvent>>();  
  12.  
  13.     #region Add & Remove Listener  
  14.   
  15.     public static void AddListener(string messageName, MessageEvent messageEvent)  
  16.     {  
  17.         Debug.Log("AddListener Name : " + messageName);  
  18.         List<MessageEvent> list = null;  
  19.         if (MessageEventsDic.ContainsKey(messageName))  
  20.         {  
  21.             list = MessageEventsDic[messageName];  
  22.         }  
  23.         else  
  24.         {  
  25.             list = new List<MessageEvent>();  
  26.             MessageEventsDic.Add(messageName, list);  
  27.         }  
  28.         if (!list.Contains(messageEvent))  
  29.         {  
  30.             list.Add(messageEvent);  
  31.         }  
  32.     }  
  33.   
  34.     public static void RemoveListener(string messageName, MessageEvent messageEvent)  
  35.     {  
  36.         Debug.Log("RemoveListener Name : " + messageName);  
  37.         if (MessageEventsDic.ContainsKey(messageName))  
  38.         {  
  39.             List<MessageEvent> list = MessageEventsDic[messageName];  
  40.             if (list.Contains(messageEvent))  
  41.             {  
  42.                 list.Remove(messageEvent);  
  43.             }  
  44.             if (list.Count <= 0)  
  45.             {  
  46.                 MessageEventsDic.Remove(messageName);  
  47.             }  
  48.         }  
  49.     }  
  50.   
  51.     public static void RemoveAllListener()  
  52.     {  
  53.         MessageEventsDic.Clear();  
  54.     }  
  55.  
  56.     #endregion  
  57.  
  58.     #region Send Message  
  59.   
  60.     public static void SendMessage(Message message)  
  61.     {  
  62.         DoMessageDispatcher(message);  
  63.     }  
  64.   
  65.     public static void SendMessage(string name, object sender)  
  66.     {  
  67.         SendMessage(new Message(name, sender));  
  68.     }  
  69.   
  70.     public static void SendMessage(string name, object sender, object content)  
  71.     {  
  72.         SendMessage(new Message(name, sender, content));  
  73.     }  
  74.   
  75.     public static void SendMessage(string name, object sender, object content, params object[] dicParams)  
  76.     {  
  77.         SendMessage(new Message(name, sender, content, dicParams));  
  78.     }  
  79.   
  80.     private static void DoMessageDispatcher(Message message)  
  81.     {  
  82.         Debug.Log("DoMessageDispatcher Name : " + message.Name);  
  83.         if (MessageEventsDic == null || !MessageEventsDic.ContainsKey(message.Name))  
  84.             return;  
  85.         List<MessageEvent> list = MessageEventsDic[message.Name];  
  86.         for (int i = 0; i < list.Count; i++)  
  87.         {  
  88.             MessageEvent messageEvent = list[i];  
  89.             if (null != messageEvent)  
  90.             {  
  91.                 messageEvent(message);  
  92.             }  
  93.         }  
  94.     }  
  95.     #endregion  
  96. }  

[csharp]  view plain  copy  print ? UIFramework之事件系统实现 UIFramework之事件系统实现
  1. using System;  
  2. using System.Collections;  
  3. using System.Collections.Generic;  
  4.   
  5. public class Message : IEnumerable<KeyValuePair<stringobject>>  
  6. {  
  7.     private Dictionary<stringobject> DatasDic = null;  
  8.   
  9.     public string Name { getprivate set; }  
  10.     public object Sender { getprivate set; }  
  11.     public object Content { getset; }  
  12.     /// <summary>  
  13.     /// 索引器   
  14.     /// </summary>  
  15.     /// <param name="key"></param>  
  16.     /// <returns></returns>  
  17.     public object this[string key]  
  18.     {  
  19.         get  
  20.         {  
  21.             if (null == DatasDic || !DatasDic.ContainsKey(key))  
  22.                 return null;  
  23.             return DatasDic[key];  
  24.         }  
  25.         set  
  26.         {  
  27.             if (null == DatasDic)  
  28.                 DatasDic = new Dictionary<stringobject>();  
  29.             if (DatasDic.ContainsKey(key))  
  30.                 DatasDic[key] = value;  
  31.             else  
  32.                 DatasDic.Add(key, value);  
  33.         }  
  34.     }  
  35.  
  36.     #region IEnumerable implementation  
  37.   
  38.     public IEnumerator<KeyValuePair<stringobject>> GetEnumerator()  
  39.     {  
  40.         if (null == DatasDic)  
  41.             yield break;  
  42.         foreach (KeyValuePair<stringobject> kvp in DatasDic)  
  43.         {  
  44.             yield return kvp;  
  45.         }  
  46.     }  
  47.   
  48.     IEnumerator IEnumerable.GetEnumerator()  
  49.     {  
  50.         return DatasDic.GetEnumerator();  
  51.     }  
  52.  
  53.     #endregion  
  54.  
  55.     #region Message Construction Function  
  56.   
  57.     public Message(string name, object sender)  
  58.     {  
  59.         Name = name;  
  60.         Sender = sender;  
  61.         Content = null;  
  62.     }  
  63.   
  64.     public Message(string name, object sender, object content)  
  65.     {  
  66.         Name = name;  
  67.         Sender = sender;  
  68.         Content = content;  
  69.     }  
  70.   
  71.     public Message(string name, object sender, object content, params object[] _dicParams)  
  72.     {  
  73.         Name = name;  
  74.         Sender = sender;  
  75.         Content = content;  
  76.         if (_dicParams.GetType() == typeof(Dictionary<stringobject>))  
  77.         {  
  78.             foreach (object _dicParam in _dicParams)  
  79.             {  
  80.                 foreach (KeyValuePair<stringobject> kvp in _dicParam as Dictionary<stringobject>)  
  81.                 {  
  82.                     //DatasDic[kvp.Key] = kvp.Value;  //error  
  83.                     this[kvp.Key] = kvp.Value;  
  84.                 }  
  85.             }  
  86.         }  
  87.     }  
  88.   
  89.     public Message(Message message)  
  90.     {  
  91.         Name = message.Name;  
  92.         Sender = message.Sender;  
  93.         Content = message.Content;  
  94.         foreach (KeyValuePair<stringobject> kvp in message.DatasDic)  
  95.         {  
  96.             this[kvp.Key] = kvp.Value;  
  97.         }  
  98.     }  
  99.  
  100.     #endregion  
  101.  
  102.     #region Add & Remove  
  103.   
  104.     public void Add(string key, object value)  
  105.     {  
  106.         this[key] = value;  
  107.     }  
  108.   
  109.     public void Remove(string key)  
  110.     {  
  111.         if (null != DatasDic && DatasDic.ContainsKey(key))  
  112.         {  
  113.             DatasDic.Remove(key);  
  114.         }  
  115.     }  
  116.     #endregion  
  117.  
  118.     #region Send  
  119.   
  120.     public void Send()  
  121.     {  
  122.         MessageCenter.SendMessage(this);  
  123.     }  
  124.  
  125.     #endregion  
  126.   
  127. }  

该事件系统的关键字就是通过创建的Message里的Name来判断的,所以要注意Name防止重复。

测试文件如下:

[csharp]  view plain  copy  print ? UIFramework之事件系统实现 UIFramework之事件系统实现
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. public class MessageCenterTest : MonoBehaviour {  
  5.   
  6.     private readonly string test = "test";  
  7.     void Awake()  
  8.     {  
  9.         MessageCenter.AddListener(test,OnMessageCome);  
  10.     }  
  11.   
  12.     private void OnMessageCome(Message message)  
  13.     {  
  14.         Debug.LogError("--->" + message["gold"]);  
  15.     }  
  16.   
  17.     void OnGUI()  
  18.     {  
  19.         if (GUI.Button(new Rect(50, 50, 150, 30), "OnMessageCome"))  
  20.         {  
  21.             Message message = new Message(test,this);  
  22.             message["gold"] = 100;  
  23.             message.Send();  
  24.         }  
  25.     }  
  26. }  


=====================================================================

结束。