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

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

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

public event EventHandler TestEvent;
AI 代码解读

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

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

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

public event EventHandler Closed
{
    add{}
    remove{}
}
AI 代码解读

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

/// <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 { }
    }
}
AI 代码解读

原来的代码中 ei.DeclaringType.GetField("Event_" + ei.Name, bindingFlags);的Event后面没有下划线,即写成了“Event”,执行时发现fi是空。参考上面的代码“_EventAll”,加一个下划线尝试。成功!
记录,以备后查。

_

目录
打赏
0
0
0
1
1221
分享
相关文章
C# WPF 中 外部图标引入iconfont,无法正常显示问题 【小白记录】
本文介绍了在C# WPF应用程序中引入外部iconfont图标时可能遇到的显示问题及其解决方法:1) 检查资源路径和引入格式是否正确,确保字体文件引用格式为“#xxxx”,并正确指向字体文件位置;2) 确保图标资源被包含在程序集中,通过设置字体文件的生成操作为Resource(资源)来实现。
C# WPF 中 外部图标引入iconfont,无法正常显示问题 【小白记录】
C# + WPF 音频播放器 界面优雅,体验良好
【9月更文挑战第18天】这是一个用 C# 和 WPF 实现的音频播放器示例,界面简洁美观,功能丰富。设计包括播放/暂停按钮、进度条、音量控制滑块、歌曲列表和专辑封面显示。功能实现涵盖音频播放、进度条控制、音量调节及歌曲列表管理。通过响应式设计、动画效果、快捷键支持和错误处理,提升用户体验。可根据需求扩展更多功能。
200 3
|
6月前
|
C#
C#一分钟浅谈:委托与事件的实现方式
本文详细介绍了C#编程中委托与事件的基础知识及应用场景。首先解释了委托的概念,包括定义与使用方法;接着介绍了事件这一基于委托的特殊类型,展示了如何在类中定义事件及跨类订阅与处理事件;最后讨论了常见问题如事件未处理异常、重复订阅及内存泄漏等,并提出了相应的解决方案。通过本文,读者将全面掌握委托与事件的使用技巧,提升应用程序的设计与开发水平。
217 7
全面掌握Unity游戏开发核心技术:C#脚本编程从入门到精通——详解生命周期方法、事件处理与面向对象设计,助你打造高效稳定的互动娱乐体验
【8月更文挑战第31天】Unity 是一款强大的游戏开发平台,支持多种编程语言,其中 C# 最为常用。本文介绍 C# 在 Unity 中的应用,涵盖脚本生命周期、常用函数、事件处理及面向对象编程等核心概念。通过具体示例,展示如何编写有效的 C# 脚本,包括 Start、Update 和 LateUpdate 等生命周期方法,以及碰撞检测和类继承等高级技巧,帮助开发者掌握 Unity 脚本编程基础,提升游戏开发效率。
222 0
模块化革命:揭秘WPF与微服务架构的完美融合——从单一职责原则到事件聚合器模式,构建高度解耦与可扩展的应用程序
【8月更文挑战第31天】本文探讨了如何在Windows Presentation Foundation(WPF)应用中借鉴微服务架构思想,实现模块化设计。通过将WPF应用分解为独立的功能模块,并利用事件聚合器实现模块间解耦通信,可以有效提升开发效率和系统可维护性。文中还提供了具体示例代码,展示了如何使用事件聚合器进行模块间通信,以及如何利用依赖注入进一步提高模块解耦程度。此方法不仅有助于简化复杂度,还能使应用更加灵活易扩展。
159 0
|
7月前
|
C# 委托
C# 委托
60 0
C# 事件
C# 面向对象编程(二)——继承
64 0
|
7月前
|
C#
C# WPF 将第三方DLL嵌入 exe
C# WPF 将第三方DLL嵌入 exe
134 0
WPF/C#:实现导航功能
WPF/C#:实现导航功能
164 0
WPF/C#:在WPF中如何实现依赖注入
WPF/C#:在WPF中如何实现依赖注入
150 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等