摘要: 在WPF中,移除一个事件中已经注册的处理方法,看似简单,实际仍是很痛苦的一件事情。由于C#的灵活性,定义事件的方法也是多种多样。我本身定义了一个事件: public event EventHandler TestEvent; 当我想注销这个事件上注册的全部方法的时候,我能够按以下的方法进行 Delegate[] dels = TestEvent.this
在WPF中,移除一个事件中已经注册的处理方法,看似简单,实际仍是很痛苦的一件事情。由于C#的灵活性,定义事件的方法也是多种多样。
我本身定义了一个事件:3d
public event EventHandler TestEvent;
当我想注销这个事件上注册的全部方法的时候,我能够按以下的方法进行code
Delegate[] dels = TestEvent.GetInvocationList(); foreach (var d in dels) { TestEvent-= d as EventHandler; }
可是,当我想注销一个Window上的Closed上注册的事件时,发如今Closed上根本没有GetInvocationList方法。这是怎么回事呢。经过反编译查看微软的代码,它的定义是这样的:对象
public event EventHandler Closed { add{} remove{} }
坑爹啊。度娘了半天,终于找到下面的方法参考完成。blog
/// <summary> /// 清除一个对象的某个事件所挂钩的delegate /// </summary> /// <param name="ctrl">控件对象</param> /// <param name="eventName">事件名称,默认的</param> public static void ClearEvents(this object ctrl, string eventName = "_EventAll") { if (ctrl == null) return; BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Static; EventInfo[] events = ctrl.GetType().GetEvents(bindingFlags); if (events == null || events.Length < 1) return; for (int i = 0; i < events.Length; i++) { try { EventInfo ei = events[i]; //只删除指定的方法,默认是_EventAll,前面加_是为了和系统的区分,防之后雷同 if (eventName != "_EventAll" && ei.Name != eventName) continue; /******************************************************** * class的每一个event都对应了一个同名(变了,前面加了Event前缀)的private的delegate类 * 型成员变量(这点能够用Reflector证明)。由于private成 * 员变量没法在基类中进行修改,因此为了可以拿到base * class中声明的事件,要从EventInfo的DeclaringType来获取 * event对应的成员变量的FieldInfo并进行修改 ********************************************************/ FieldInfo fi = ei.DeclaringType.GetField("Event_" + ei.Name, bindingFlags); if (fi != null) { // 将event对应的字段设置成null便可清除全部挂钩在该event上的delegate fi.SetValue(ctrl, null); } } catch { } } }
原来的代码中 ei.DeclaringType.GetField("Event_" + ei.Name, bindingFlags);的Event后面没有下划线,即写成了“Event”,执行时发现fi是空。参考上面的代码“_EventAll”,加一个下划线尝试。成功!
记录,以备后查。事件