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

_

目录
相关文章
|
1月前
|
C#
由浅入深理解C#中的事件
由浅入深理解C#中的事件
95 19
|
2天前
|
C#
C#一分钟浅谈:委托与事件的实现方式
本文详细介绍了C#编程中委托与事件的基础知识及应用场景。首先解释了委托的概念,包括定义与使用方法;接着介绍了事件这一基于委托的特殊类型,展示了如何在类中定义事件及跨类订阅与处理事件;最后讨论了常见问题如事件未处理异常、重复订阅及内存泄漏等,并提出了相应的解决方案。通过本文,读者将全面掌握委托与事件的使用技巧,提升应用程序的设计与开发水平。
17 7
|
11天前
|
图形学 C# 开发者
全面掌握Unity游戏开发核心技术:C#脚本编程从入门到精通——详解生命周期方法、事件处理与面向对象设计,助你打造高效稳定的互动娱乐体验
【8月更文挑战第31天】Unity 是一款强大的游戏开发平台,支持多种编程语言,其中 C# 最为常用。本文介绍 C# 在 Unity 中的应用,涵盖脚本生命周期、常用函数、事件处理及面向对象编程等核心概念。通过具体示例,展示如何编写有效的 C# 脚本,包括 Start、Update 和 LateUpdate 等生命周期方法,以及碰撞检测和类继承等高级技巧,帮助开发者掌握 Unity 脚本编程基础,提升游戏开发效率。
27 0
|
11天前
|
C# 微服务 Windows
模块化革命:揭秘WPF与微服务架构的完美融合——从单一职责原则到事件聚合器模式,构建高度解耦与可扩展的应用程序
【8月更文挑战第31天】本文探讨了如何在Windows Presentation Foundation(WPF)应用中借鉴微服务架构思想,实现模块化设计。通过将WPF应用分解为独立的功能模块,并利用事件聚合器实现模块间解耦通信,可以有效提升开发效率和系统可维护性。文中还提供了具体示例代码,展示了如何使用事件聚合器进行模块间通信,以及如何利用依赖注入进一步提高模块解耦程度。此方法不仅有助于简化复杂度,还能使应用更加灵活易扩展。
29 0
|
23天前
|
存储 算法 安全
C#语言进阶(二)—事件全解
C#语言进阶(二)—事件全解
25 0
|
1月前
|
前端开发 C# 容器
WPF/C#:实现导航功能
WPF/C#:实现导航功能
35 0
|
1月前
|
设计模式 测试技术 C#
WPF/C#:在WPF中如何实现依赖注入
WPF/C#:在WPF中如何实现依赖注入
32 0
|
1月前
|
前端开发 C# Windows
WPF/C#:如何实现拖拉元素
WPF/C#:如何实现拖拉元素
40 0
|
1月前
|
存储 C# 索引
WPF/C#:BusinessLayerValidation
WPF/C#:BusinessLayerValidation
27 0
|
1月前
|
C#
WPF/C#:数据绑定到方法
WPF/C#:数据绑定到方法
28 0