c# 利用反射清除事件
控件的事件清除,除了-=,就只能依靠反射来执行了。
/// <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 < ) return; for (int i = ; 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 { }
}
}
当前使用环境.net 4.0。参考了很多其他人的代码,有三个地方值得注意。
一个是eventName,GetField的时候在原来的Name前面加"Event"前缀。这个可能在不同的.net版本不一样,出现过三种:eventName,"Event"+eventName, "Event_" + controlType.Name + eventname.
第二个:BindingFlags。尽量用Public | NonPublic | Instance | IgnoreCase | Static。
第三:GetField的执行对象用EventInfo.DeclaringType,否则有可能继承的类获取不到数据。
补充一个测试。下面的代码中Button会执行三次-=然后+=,但是每次的对象都是重新new的。三次绑定后,点击button1时,只执行一次输出。
public Form1()
{
this.Load += (a, b) =>
{
new Thread(new ThreadStart(() =>
{
int i = ;
while (true)
{
if (button1.InvokeRequired) button1.Invoke(new Action(ReBindEvent));
else ReBindEvent();
Thread.Sleep();
i++;
if (i >= ) break;
}
})).Start();
};
} void ReBindEvent()
{
button1.Click -= GetClickHandle();
button1.Click += GetClickHandle();
} EventHandler GetClickHandle()
{
return new EventHandler((a, b) =>
{
Console.WriteLine(DateTime.Now + " 执行一次");
});
}
c# 利用反射清除事件的更多相关文章
- 利用反射绑定事件处理程序(C#)
利用反射绑定事件处理程序(C#) 传统的写法:强类型的情况下 using System;using System.Collections.Generic;using System.Text; usin ...
- C# 调用一个按钮的Click事件(利用反射)
最基本的调用方法 (1)button1.PerformClick();(2)button1_Click(null,null);(3)button_Click(null,new EventArgs()) ...
- 利用反射--调用一个按钮的Click事件
最基本的调用方法 (1)button1.PerformClick();(2)button1_Click(null,null);(3)button_Click(null,new EventArgs()) ...
- [.net 面向对象程序设计进阶] (20) 反射(Reflection)(上)利用反射技术实现动态编程
[.net 面向对象程序设计进阶] (20) 反射(Reflection)(上)利用反射技术实现动态编程 本节导读:本节主要介绍什么是.NET反射特性,.NET反射能为我们做些什么,最后介绍几种常用的 ...
- C#回顾 - 8.利用反射动态创建对象
拿微信消息返回的示例数据实验 var data = "<xml><ToUserName><![CDATA[toUser]]></ToUserName ...
- Python基础篇【第3篇】: Python异常处理、反射、动态导入、利用反射的web框架
异常处理 什么是异常? 异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行. 一般情况下,在Python无法正常处理程序时就会发生一个异常.异常是Python对象,表示一个错误.当P ...
- c#反射机制学习和利用反射获取类型信息
反射(Reflection)是.NET中的重要机制,通过放射,可以在运行时获得.NET中每一个类型(包括类.结构.委托.接口和枚举等)的成员,包括方法.属性.事件,以及构造函数等.还可以获得每个成员的 ...
- 利用反射修改final数据域
当final修饰一个数据域时,意义是声明该数据域是最终的,不可修改的.常见的使用场景就是eclipse自动生成的serialVersionUID一般都是final的. 另外还可以构造线程安全(thre ...
- 利用反射快速给Model实体赋值 使用 Task 简化异步编程 Guid ToString 格式知多少?(GUID 格式) Parallel Programming-实现并行操作的流水线(生产者、消费者) c# 无损高质量压缩图片代码 8种主要排序算法的C#实现 (一) 8种主要排序算法的C#实现 (二)
试想这样一个业务需求:有一张合同表,由于合同涉及内容比较多所以此表比较庞大,大概有120多个字段.现在合同每一次变更时都需要对合同原始信息进行归档一次,版本号依次递增.那么我们就要新建一张合同历史表, ...
随机推荐
- 项目记录25--unity-tolua框架 View02---BasePanel.lua
还在,还在. ... . 每天晚上找点时间写点点,多了也不想学到底是什么心理啊. 写完看电影去. 今天写两个算超完毕了BaseUI.lua,UIManager.lua(完好中这个) local Bas ...
- stm32定时器主从模式
TIM2作master:TIM3,TIM4作slave 定时器2事件更新被用作触发输出TRGO 从定时器TIM3,TIM4工作在从模式:门控模式 触发选择设为:ITR1,这样TIM2的TRGO就连到了 ...
- Python常见问题系列
Python基础题1.冒泡排序 def mao_pao(li): for i in range(len(li)): for j in range(len(li)): if li[i] < li[ ...
- Android百日程序 开篇章:Intent打开网页
学习一下人家100日写100个网页的做法,我也用100日写100个完整的Android程序. 这些程序的最基本要求: 1 完整性-每一个程序都必须是独立可执行的 2 不反复性-所用的重点知识点都不一样 ...
- Android开发:SharedPreferences 存储数据、获取数据
Android开发:SharedPreferences 存储数据.获取数据 email:chentravelling@163.com 开发环境:win7 64位,Android Studio. 关于S ...
- vim常忘命令
1.复制指定行到当前光标的下一行. #假设当前光标在10行,想把第5行复制到第11行 :5copy. #copy命令有2种简写'co'和't',所以也可以写成下面的格式 :5co. :5t. 参考:h ...
- mysql获得60天前unix时间示例
在mysql中获取多少天前的unix时间的方法.首先根据now()获得当前时间,使用adddate()方法获得60天前时间,使用unix_timestamp()方法转换时间类型 select UNIX ...
- 看了一下unity5.6的新功能 以及Timeline
3月31日unity5.6发布,然而timeline(前sequence模块)被delay到unity 2017.上个星期官方又发布了unity 2017的beta版本 抽空看了下 (unity5.6 ...
- IOS 学习 Key-value coding
1 前言 本节我们主要介绍键值编码,以及如何使一个类符合KVC编码. 2 详述 键-值编码是一个对于间接访问一个对象属性和关系使用字符标识的机制.它支持或者关系几个特别的Cocoa编程机制和技术,在C ...
- WCF返回null超时
Message.CreateMessage(msg.Version, msg.Headers.Action + "Response", DealObject("错误信息& ...