清除事件所有委托方法

问题背景

在做winform报表开发时,FastReport是一个很好的工具,它提供了一些封装好的控件,可以很方便快速的开发打印报表。其中有一个控件是用于预览报表的,所有功能按钮事件方法都是封装好的。

一般情况下这些功能按钮封装好的事件能满足基本的使用,不需要写多余的代码,但是在实际使用过程中,经常会遇到一些需要保存打印记录等操作情景,原有的按钮事件无法满足,就有了需要替换掉原按钮事件调用的方法的需求。

解决方案

因为控件是封装好的,无法直接知道事件具体调用哪些方法,通过 -= 的方式取消订阅事件,于是便想到了反射,通过反射将该事件的调用列表获取出来,然后全部清除掉,再通过 += 的方式订阅自定义方法。经过一番资料查找,整理出了一个帮助类:

 public static class EventHelper
 {
        private const BindingFlags BINDINGFLAGS = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Static;

        /// <summary>
        /// 获取事件委托调用列表
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="obj">事件所属对象</param>
        /// <param name="eventName">事件名称</param>
        /// <returns></returns>
        public static Delegate[] GetInvocationList<T>(this T obj, string eventName) where T : class
        {
            if (obj == null || string.IsNullOrEmpty(eventName))
            {
                return null;
            }
            var eventInfo = obj.GetType().GetEvent(eventName);
            if (eventInfo == null)
            {
                return null;
            }
            Delegate d = null;
            var fieldInfo = eventInfo.DeclaringType.GetField(eventName, BINDINGFLAGS);
            if (fieldInfo != null)
            {
                d = (Delegate)fieldInfo.GetValue(obj);
                return d == null ? null : d.GetInvocationList();
            }
            fieldInfo = eventInfo.DeclaringType.GetField("Event" + eventName, BINDINGFLAGS);
            if (fieldInfo == null)
            {
                fieldInfo = eventInfo.DeclaringType.GetField("EVENT_" + eventName.ToUpper(), BINDINGFLAGS);
            }
            if (fieldInfo == null)
            {
                return null;
            }
            PropertyInfo propertyInfo = obj.GetType().GetProperty("Events", BINDINGFLAGS);
            EventHandlerList eventHandlerList = (EventHandlerList)propertyInfo.GetValue(obj, null);
            d = eventHandlerList[fieldInfo.GetValue(obj)];
            return d == null ? null : d.GetInvocationList();
        }

        /// <summary>
        /// 清除事件委托调用列表
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="obj">事件所属对象</param>
        /// <param name="eventName">事件名称</param>
        public static void ClearInvocationList<T>(this T obj, string eventName) where T : class
        {
            var handlers = obj.GetInvocationList(eventName);
            if (handlers == null)
            {
                return;
            }
            var eventInfo = obj.GetType().GetEvent(eventName);
            foreach (var handler in handlers)
            {
                eventInfo.RemoveEventHandler(obj, handler);//移除已订阅的eventName类型事件
            }
        }
   }

通过这个帮助类,可以方便的获取或清除事件的调用列表,使用方式如下:

button.GetInvocationList("Click");
button.ClearInvocationList("Click");

PS:学业不精,有些专业知识理解的不是很透彻,术语maybe不正确导致阅读理解错误,大神不理赐教。

时间: 2024-10-16 17:06:27

清除事件所有委托方法的相关文章

取消事件所有委托方法

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using System.ComponentModel; namespace ConsoleApplication3 { class Program { static void Main(string[] args) { ProtocolEvent c = new Protoc

C#学习:委托、事件、匿名方法

一.委托: 委托给我的感觉就是一个种类型,可以让方法更具面向对象的特性——你看,其实我也没说明白,因为我也不大理解.还是一步步往下学吧. 具体来说,委托就是一个类似下面的这种东西: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace ConsoleTestCsharp { class Program { d

关于事件、委托、被调用方法的详解

先上图: 大概就是这样,有5个radiobutton和5个fragment,要做的是选中按钮和页面的对应Show(). 然而,当执行到 radioButton[0].Checked = true; 之后,事件CheckedChange被触发,i的值会显示为5,提示数组越界. Why?这里就要涉及到关于事件→委托→被调用方法的关系问题:(以下均为个人理解) !即是:事件封装委托,委托指向方法! 关键点如下: 1.这里使用的是lambda表达式调用匿名方法,原理上也是一种委托,只是匿名方法原封不动地

JS事件冒泡机制以及委托方法,以及vue中的stop

要理解事件冒泡机制,就得先了解事件. 浏览器是事件驱动型的,根据用户的行为触发不同的事件,根据事件执行相应的操作.我们较为熟悉的事件有三大类型:鼠标键盘事件.页面事件.表单相关事件. 鼠标键盘事件:onclick.ondbclick.onmousedown.onmouseup.onmouseover.onmousemove.onmouseout.onkeypress.onkeydown.onkeyup: 页面事件:onload.onunload.onresize.onerror.onabort:

C# 事件与委托的区别

C# 事件与委托的区别 先看一段程序 class Program { static void Main(string[] args) { Test obj = new Test(); obj.print += printout1; //绑定printout1方法 obj.print += printout2; //绑定printout2方法 obj.start(); } static void printout1() { Console.WriteLine("输出第一段字符串"); }

从事件来看委托

事件是基于委托,为委托提供了一种发布/订阅机制,在dotNet到处都能看到事件,一个简单的例子就是在windows应用程序中,Button类提供了Click事件,这类事件就是委托,触发Click事件时调用的处理程序方法需要定义,其参数也是由委托类型定义的,事件模型可以用下图简要说明. 在这个模型中,事件的响应者通过订阅关系直接关联在事件拥有者的事件上,我们把这种事件模型或者CLR事件模型.因为CLR事件本质上是一个委托实例,我们暂且模仿CLR属性的说法,把CLR事件定义为一个委托类型实例的包装器

C# 事件和委托

1 public class Heater { 2 private int temperature; 3 public string type = "RealFire 001"; // 添加型号作为演示 4 public string area = "China Xian"; // 添加产地作为演示 5 //声明委托 6 public delegate void BoiledEventHandler(Object sender, BoiledEventArgs e)

事件与委托

C# 中的委托和事件 文中代码在VS2005下通过,由于VS2003(.Net Framework 1.1)不支持隐式的委托变量,所以如果在一个接受委托类型的位置直接赋予方法名,在VS2003下会报错,解决办法是显式的创建一个委托类型的实例(委托变量).例如:委托类型 委托实例 = new 委托类型(方法名); 引言 委托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太容易

事件和委托

委托:对方法的绑定 事件和委托的步骤1.定义委托public delegate 返回值 委托名(参数);2.基于委托定义事件public event 委托名 事件名; 3.注册事件对象.事件名 += new 委托(方法); 4.触发事件 先检查事件是否有人注册,有则触发 if (事件名 != null) 事件名(); 事件和委托,布布扣,bubuko.com