问题背景
在做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