前言
在开发Android或Vue前端的时候,我们可能数据产生后需要在多个页面接收,这时候可以用EventBus来实现,那么WPF开发能用EventBus吗?我没就来尝试一下!
EventBus
事件实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| using System;
namespace SchoolClient.Utils.EventBus { public interface IEventData { DateTime EventTime { get; set; }
object EventSource { get; set; } }
public class EventData : IEventData { public DateTime EventTime { get; set; }
public Object EventSource { get; set; }
public EventData() { EventTime = DateTime.Now; } } }
|
事件处理类接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| namespace SchoolClient.Utils.EventBus { public interface IEventHandler { }
public interface IEventHandler<TEventData> : IEventHandler where TEventData : IEventData { void HandleEvent(TEventData eventData); } }
|
EventBus
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
| using SchoolClient.Utils.EventBus;
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Reflection;
namespace SchoolClient.Utils { public class ZEventBus { public static ZEventBus Instance = new ZEventBus();
private readonly ConcurrentDictionary<Type, List<Type>> _eventAndHandlerMapping;
public ZEventBus() { _eventAndHandlerMapping = new ConcurrentDictionary<Type, List<Type>>(); }
public void RegisterAll() { Assembly assembly = Assembly.GetEntryAssembly(); foreach (var type in assembly.GetTypes()) { if (typeof(IEventHandler).IsAssignableFrom(type)) { Type handlerInterface = type.GetInterface("IEventHandler`1"); if (handlerInterface != null) { Type eventDataType = handlerInterface.GetGenericArguments()[0]; if (_eventAndHandlerMapping.ContainsKey(eventDataType)) { List<Type> handlerTypes = _eventAndHandlerMapping[eventDataType]; handlerTypes.Add(type); _eventAndHandlerMapping[eventDataType] = handlerTypes; } else { var handlerTypes = new List<Type> { type }; _eventAndHandlerMapping[eventDataType] = handlerTypes; } } } } }
public void Register<TEventData>(Type eventHandler) { List<Type> handlerTypes; if (_eventAndHandlerMapping.ContainsKey(typeof(TEventData))) { handlerTypes = _eventAndHandlerMapping[typeof(TEventData)]; } else { handlerTypes = new List<Type>(); } if (!handlerTypes.Contains(eventHandler)) { handlerTypes.Add(eventHandler); } _eventAndHandlerMapping[typeof(TEventData)] = handlerTypes; }
public void UnRegister<TEventData>(Type eventHandler) { if (_eventAndHandlerMapping.ContainsKey(typeof(TEventData))) { List<Type> handlerTypes = _eventAndHandlerMapping[typeof(TEventData)]; if (handlerTypes.Contains(eventHandler)) { handlerTypes.Remove(eventHandler); _eventAndHandlerMapping[typeof(TEventData)] = handlerTypes; } } }
public void PostEvent<TEventData>(TEventData eventData) where TEventData : IEventData {
if (_eventAndHandlerMapping.ContainsKey(eventData.GetType())) { List<Type> handlers = _eventAndHandlerMapping[eventData.GetType()]; if (handlers != null && handlers.Count > 0) { foreach (var handler in handlers) { MethodInfo methodInfo = handler.GetMethod("HandleEvent"); if (methodInfo != null) { object obj = Activator.CreateInstance(handler); methodInfo.Invoke(obj, new object[] { eventData }); } } } } } } }
|
项目中使用
数据
1 2 3 4 5 6 7 8 9 10 11
| namespace SchoolClient.Socket { public class SocketEvent : EventData { public ZWsMsgVo Msg { get; set; }
public SocketEvent() { } } }
|
项目中Event接收类
1 2 3 4 5 6 7 8
| class MyClass : IEventHandler<SocketEvent> { public void HandleEvent(SocketEvent eventData) { var msg = JsonConvert.SerializeObject(eventData); Console.WriteLine("EventBus:"+ msg); } }
|
只要调用
1
| ZEventBus.Instance.RegisterAll();
|
或者
1
| ZEventBus.Instance.Register<SocketEvent>(GetType());
|
这两种的任何一种方式注册后,都会收到事件
发送事件
1
| ZEventBus.Instance.PostEvent<SocketEvent>(msgEvent);
|
问题
注意这个代码
1 2 3 4 5 6
| MethodInfo methodInfo = handler.GetMethod("HandleEvent"); if (methodInfo != null) { object obj = Activator.CreateInstance(handler); methodInfo.Invoke(obj, new object[] { eventData }); }
|
我们可以看出上面的实现的原理是通过反射找到类里的方法,然后创建类的实例调用其中的HandleEvent方法,所以问题就来了,我们没法用在Window对应的类上,因为该类无法在非UI线程中创建。
那么是不是可以直接保留类实例的引用,然后进行调用呢?
答案是不能
在运行时Window的子类通过一下方式获取Type
获取到的都是System.RuntimeType,也无法通过强转调用其中的方法。
所以目前还未实现能在Window的子类中使用EventBus