前言
在开发Android或Vue前端的时候,我们可能数据产生后需要在多个页面接收,这时候可以用EventBus来实现,那么WPF开发能用EventBus吗?我没就来尝试一下!
EventBus
事件实体类
代码语言:javascript复制using System;
namespace SchoolClient.Utils.EventBus
{
/// <summary>
/// 定义事件源接口,所有的事件源都要实现该接口
/// </summary>
public interface IEventData
{
/// <summary>
/// 事件发生的时间
/// </summary>
DateTime EventTime { get; set; }
/// <summary>
/// 触发事件的对象
/// </summary>
object EventSource { get; set; }
}
public class EventData : IEventData
{
/// <summary>
/// 事件发生的时间
/// </summary>
public DateTime EventTime { get; set; }
/// <summary>
/// 触发事件的对象
/// </summary>
public Object EventSource { get; set; }
public EventData()
{
EventTime = DateTime.Now;
}
}
}
事件处理类接口
代码语言:javascript复制namespace SchoolClient.Utils.EventBus
{
public interface IEventHandler
{
}
public interface IEventHandler<TEventData> : IEventHandler where TEventData : IEventData
{
/// <summary>
/// 事件处理器实现该方法来处理事件
/// </summary>
/// <param name="eventData"></param>
void HandleEvent(TEventData eventData);
}
}
EventBus
代码语言:javascript复制
using SchoolClient.Utils.EventBus;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection;
namespace SchoolClient.Utils
{
/// <summary>
/// 事件总线
/// </summary>
public class ZEventBus
{
public static ZEventBus Instance = new ZEventBus();
/// <summary>
/// 定义线程安全集合
/// </summary>
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))//判断当前类型是否实现了IEventHandler接口
{
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;
}
}
}
}
}
/// <summary>
/// 手动绑定事件源与事件处理
/// </summary>
/// <typeparam name="TEventData"></typeparam>
/// <param name="eventHandler"></param>
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;
}
/// <summary>
/// 手动解除事件源与事件处理的绑定
/// </summary>
/// <typeparam name="TEventData"></typeparam>
/// <param name="eventHandler"></param>
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;
}
}
}
/// <summary>
/// 根据事件源触发绑定的事件处理
/// </summary>
/// <typeparam name="TEventData"></typeparam>
/// <param name="eventData"></param>
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 });
}
}
}
}
}
}
}
项目中使用
数据
代码语言:javascript复制namespace SchoolClient.Socket
{
public class SocketEvent : EventData
{
public ZWsMsgVo Msg { get; set; }
public SocketEvent()
{
}
}
}
项目中Event接收类
代码语言:javascript复制class MyClass : IEventHandler<SocketEvent>
{
public void HandleEvent(SocketEvent eventData)
{
var msg = JsonConvert.SerializeObject(eventData);
Console.WriteLine("EventBus:" msg);
}
}
只要调用
代码语言:javascript复制ZEventBus.Instance.RegisterAll();
或者
代码语言:javascript复制ZEventBus.Instance.Register<SocketEvent>(GetType());
这两种的任何一种方式注册后,都会收到事件
发送事件
代码语言:javascript复制ZEventBus.Instance.PostEvent<SocketEvent>(msgEvent);
问题
注意这个代码
代码语言:javascript复制MethodInfo methodInfo = handler.GetMethod("HandleEvent");
if (methodInfo != null)
{
object obj = Activator.CreateInstance(handler);
methodInfo.Invoke(obj, new object[] { eventData });
}
我们可以看出上面的实现的原理是通过反射找到类里的方法,然后创建类的实例调用其中的HandleEvent
方法,所以问题就来了,我们没法用在Window对应的类上,因为该类无法在非UI线程中创建。
那么是不是可以直接保留类实例的引用,然后进行调用呢?
答案是不能
在运行时Window
的子类通过一下方式获取Type
obj.GetType();
获取到的都是System.RuntimeType
,也无法通过强转调用其中的方法。
所以目前还未实现能在Window的子类中使用EventBus