在C#编程中,事件处理是一个常见的任务。通常情况下,事件源和事件处理器的生命周期是匹配的,即它们同时创建和销毁。然而,有时候事件源可能会比事件处理器活得更久。例如,最近遇到了一个场景,需要监听Clipboard.ContextChanged事件,这是一个静态事件。在WPF中,可以使用WeakEventManager类来处理这种情况,但是在Window Store应用中,这个类并不可用。因此,需要自己构建一个类似的机制。
为了解决这个问题,创建了一个自定义的WeakEventManager类。这个类允许事件处理器在没有其他引用的情况下被垃圾回收。以下是如何注册事件的示例代码:
WeakEventManager.AddHandler
以下是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类必须以一种方式包装事件处理器委托的部分,允许目标类被垃圾回收。