实现WeakEventManager以处理事件源的长生命周期问题

在C#编程中,事件处理是一个常见的任务。通常情况下,事件源和事件处理器的生命周期是匹配的,即它们同时创建和销毁。然而,有时候事件源可能会比事件处理器活得更久。例如,最近遇到了一个场景,需要监听Clipboard.ContextChanged事件,这是一个静态事件。在WPF中,可以使用WeakEventManager类来处理这种情况,但是在Window Store应用中,这个类并不可用。因此,需要自己构建一个类似的机制。

为了解决这个问题,创建了一个自定义的WeakEventManager类。这个类允许事件处理器在没有其他引用的情况下被垃圾回收。以下是如何注册事件的示例代码: WeakEventManager.AddHandler( typeof(Clipboard), "ContentChanged", this.OnClipboardContentChanged);

以下是WeakEventManager类的主要实现。这个类使用了一个内部类来处理实际的逻辑: using System; using System.Collections.Generic; using System.Reflection; public static class WeakEventManager { private readonly static List registeredEvents = new List(); public static void AddHandler(Type sourceType, string eventName, EventHandler handler) { EventInfo eventInfo = sourceType.GetRuntimeEvent(eventName); registeredEvents.Add(new WeakEvent(null, eventInfo, handler)); } public static void AddHandler(TEventSource source, string eventName, EventHandler handler) { EventInfo eventInfo = typeof(TEventSource).GetRuntimeEvent(eventName); registeredEvents.Add(new WeakEvent(source, eventInfo, handler)); } public static void RemoveHandler(Type sourceType, string eventName, EventHandler handler) { EventInfo eventInfo = sourceType.GetRuntimeEvent(eventName); foreach (WeakEvent weakEvent in registeredEvents) { if (weakEvent.IsEqualTo(null, eventInfo, handler)) { weakEvent.Detach(); break; } } } public static void RemoveHandler(TEventSource source, string eventName, EventHandler handler) { EventInfo eventInfo = typeof(TEventSource).GetRuntimeEvent(eventName); foreach (WeakEvent weakEvent in registeredEvents) { if (weakEvent.IsEqualTo(source, eventInfo, handler)) { weakEvent.Detach(); break; } } } private class WeakEvent { // Implementation details to follow } }

在生产环境中,可能需要进行一些参数验证(例如,确保没有null值,并且GetRuntimeEvent返回了有效的结果),但为了保持代码简单,省略了这些验证。实际的逻辑是在WeakEvent内部类中实现的。这个类是必要的,因为不能仅仅保持对事件处理器对象的弱引用,因为这很可能是一个临时对象,很快就会被垃圾回收。同时,也不能保持对事件处理器的强引用,因为这会保持对目标实例的引用,从而破坏了这个类的目的!因此,WeakEvent类必须以一种方式包装事件处理器委托的部分,允许目标类被垃圾回收。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485