C#(WPF)去除事件中注册的事件处理方法!

摘要: 在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”,加一个下划线尝试。成功!
记录,以备后查。事件

_

相关文章
相关标签/搜索