1. 程式人生 > >清除事件所有委托方法

清除事件所有委托方法

出了 使用方式 直接 多余 his ima oid cas 分享圖片

問題背景

在做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不正確導致閱讀理解錯誤,大神不理賜教。

清除事件所有委托方法