清除事件所有委托方法


問題背景

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM