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

原文链接:点击打开链接

摘要: 在WPF中,移除一个事件中已经注册的处理方法,看似简单,实际还是很痛苦的一件事情。因为C#的灵活性,定义事件的方法也是多种多样。我自己定义了一个事件: public event EventHandler TestEvent; 当我想注销这个事件上注册的所有方法的时候,我可以按如下的方法进行 Delegate[] dels = TestEvent.

在WPF中,移除一个事件中已经注册的处理方法,看似简单,实际还是很痛苦的一件事情。因为C#的灵活性,定义事件的方法也是多种多样。
我自己定义了一个事件:

public event EventHandler TestEvent;

当我想注销这个事件上注册的所有方法的时候,我可以按如下的方法进行

 Delegate[] dels = TestEvent.GetInvocationList();
            foreach (var d in dels)
            {
                TestEvent-= d as EventHandler;
            }

但是,当我想注销一个Window上的Closed上注册的事件时,发现在Closed上根本没有GetInvocationList方法。这是怎么回事呢。通过反编译查看微软的代码,它的定义是这样的:

public event EventHandler Closed
{
    add{}
    remove{}
}

坑爹啊。度娘了半天,终于找到下面的方法参考完成。

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

_


猜你喜欢

转载自blog.csdn.net/qq_42154484/article/details/80773756