在程序設計中有時候須要動態訂閱客戶本身的事件,調用完成後又要刪除之前訂閱的事件。由於若是不刪除,有時會形成事件是會重複訂閱,致使程序運行異常。一個辦法是用反射來控件事件列表。清空方法代碼以下:html
/// <summary>
/// 清空控件的事件列表
/// </summary>
/// <param name="pControl">要清空事件列表的控件</param>
/// <param name="pEventName">事件名</param>web
void ClearEvent(Control pControl, string pEventName)ide
{函數
if (pControl== null) return;post
if (string.IsNullOrEmpty(pEventName)) return;測試
BindingFlags mPropertyFlags = BindingFlags.Instance | BindingFlags.Publicthis
| BindingFlags.Static | BindingFlags.NonPublic;//篩選spa
BindingFlags mFieldFlags = BindingFlags.Static | BindingFlags.NonPublic;.net
Type controlType = typeof(System.Windows.Forms.Control);設計
PropertyInfo propertyInfo = controlType.GetProperty("Events", mPropertyFlags);
EventHandlerList eventHandlerList = (EventHandlerList)propertyInfo.GetValue(pControl, null);//事件列表
FieldInfo fieldInfo = (typeof(Control)).GetField("Event" + pEventName, mFieldFlags);
Delegate d = eventHandlerList[fieldInfo.GetValue(pControl)];
if (d == null) return;
EventInfo eventInfo=controlType.GetEvent(pEventName);
foreach (Delegate dx in d.GetInvocationList())
eventInfo.RemoveEventHandler(pControl, dx);//移除已訂閱的pEventName類型事件
}
這種方法能夠一勞永逸,簡單方便。但因爲引入了反射,涉及到的數據類型,編譯器是沒法檢查的,容易給程序運行時帶來不穩定因素。
以上轉載的,我是要用來判斷ArcEngine中PageLayoutControl控件的事件是否綁定處理函數的,因爲MS事件機制的修改,已經不能經過==null的方式來判斷事件是否綁定函數了,須要用到反射,這個例子雖然短,不過恰好能說明狀況
Type t = typeof(AxPageLayoutControl);
System.Reflection.FieldInfo fieldInfo = t.GetField("OnDoubleClick", myBindingFlags);
Delegate instanceDelegate = fieldInfo.GetValue(axPageLayoutControl1) as Delegate;
string msg = "";
if (instanceDelegate != null)
{
foreach (Delegate d in instanceDelegate.GetInvocationList())
{
//c.OnChange -= d as EventHandler;
////evt.RemoveEventHandler(c, d as EventHandler);
msg += d.Method.Name;
}
}
MessageBox.Show("deligate is:" + msg);
這樣就能把PageLayoutControl的OnDoubleClick綁定的全部函數的名稱輸出出來
能夠進一步修改
出處:http://www.cnblogs.com/caodajieup/archive/2011/09/29/2195117.html
======================================================================================================
public static Delegate[] GetComponentEventDelegate(Component component, string EventName, string EventHandlerTypeName) { Type componentType = component.GetType(); PropertyInfo eventsPropertyInfo = componentType.GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic); EventHandlerList eventHanlderList = eventsPropertyInfo.GetValue(component, null) as EventHandlerList; FieldInfo HeadFieldInfo = eventHanlderList.GetType().GetField("head", BindingFlags.Instance | BindingFlags.NonPublic); object HeadObject = HeadFieldInfo.GetValue(eventHanlderList); do { FieldInfo[] fieldInfoList = componentType.GetFields(BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fieldInfoList) { object fieldValue = fieldInfo.GetValue(component); if (fieldValue != null) { Type fieldType = fieldValue.GetType(); if (fieldType.Name == EventHandlerTypeName && (fieldValue as Delegate) != null) { return (fieldValue as Delegate).GetInvocationList(); } else if (fieldType.Name == typeof(Object).Name) { if (fieldInfo.Name.IndexOf(EventName, StringComparison.OrdinalIgnoreCase) > -1) { if (HeadObject != null) { Delegate delegateObject = eventHanlderList[fieldValue]; if (delegateObject != null) return delegateObject.GetInvocationList(); } } } } } componentType = componentType.BaseType; } while (componentType != null); if (HeadObject != null) { object ListEntry = HeadObject; Type ListEntryType = ListEntry.GetType(); FieldInfo handlerFieldInfo = ListEntryType.GetField("handler", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo keyFieldInfo = ListEntryType.GetField("key", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo nextFieldInfo = ListEntryType.GetField("next", BindingFlags.Instance | BindingFlags.NonPublic); while (ListEntry != null) { Delegate handler = handlerFieldInfo.GetValue(ListEntry) as Delegate; object key = keyFieldInfo.GetValue(ListEntry); ListEntry = nextFieldInfo.GetValue(ListEntry); if (handler != null && handler.GetType().Name == EventHandlerTypeName) return handler.GetInvocationList(); } } return null; }
簡要說明:
1)參數說明:
component: 組件對象實例
EventName: 事件的名稱,如"ItemClick"
EventHandlerTypeName: 事件委託類型,如"ItemClickEventHander"
2)代碼說明:
第一段代碼遍歷組件的全部私有字段,嘗試根據EventName和EventHandlerTypeName找出相關的字段.
若是找到了相關的字段,檢查它的值是不是Delegate類型,是的話OK.若是它的值是Object類型,那麼說明它是EventHandlerList的key,則須要用EventHandlerList實例[key]來獲得委託列表.
第二段代碼在第一段代碼沒找到對應的字段的狀況下,檢查EventHandlerList是否爲空,不爲空的話。遍歷該組件的全部事件,嘗試使用EventHandlerTypeName來找到相關的委託列表。
若是還未找到,則返回null。
3)存在的問題
可能沒法找到某些組件的委託,或者找到不匹配的委託列表。
可否順利地找到事件對應的委託列表,取決於組件內部定義的事件字段或在EventHandlerList的key字段是否與事件名稱相同以及EventHandler類型是否特殊。
若是組件內部定義了與事件名稱相同的字段或EventHandler類型比較特別,則較容易找到對應的委託列表。
雖然能夠經過EventHandlerList來獲得組件的全部事件委託,但根據獲得的key卻沒法肯定handler委託列表對應的是哪個事件。
4)已檢測過的組件和事件
沒來得及仔細測試,只測試了二個XtraBar的BarButtonItem.ItemClick和XtraNavBar的NavBarItem.LinkClicked事件。
出處:https://blog.csdn.net/zxkid/article/details/1444396
======================================================================================================
EventInfo[] memberinfo = (typeof(System.Windows.Forms.Button)).GetEvents(); foreach (EventInfo info in memberinfo) { //Console.WriteLine(info.Name); PropertyInfo propertyInfo = (typeof(System.Windows.Forms.Button)).GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic); EventHandlerList eventHandlerList = (EventHandlerList)propertyInfo.GetValue(this.button2, null); FieldInfo fieldInfo = (typeof(Control).GetField("Event" + info.Name, BindingFlags.Static | BindingFlags.NonPublic)); if (fieldInfo != null) { Delegate d = eventHandlerList[fieldInfo.GetValue(null)]; if (d != null) { listBox1.Items.Add(d.Method.Name); } } }
出處:https://ask.csdn.net/questions/264615
======================================================================================================
/// <summary> /// 移除一個對象指定事件的全部註冊的方法 /// </summary> /// <typeparam name="T">泛型</typeparam> /// <param name="obj">當前對象</param> /// <param name="eventName">事件名</param> public static void RemoveEvent<T>(T obj, string eventName) { BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static; EventInfo[] eventInfo = obj.GetType().GetEvents(bindingFlags); if (eventInfo == null) { return; } foreach (EventInfo info in eventInfo) { if (string.Compare(info.Name, eventName, StringComparison.OrdinalIgnoreCase) == 0) { FieldInfo fieldInfo = info.DeclaringType.GetField(info.Name, bindingFlags); if (fieldInfo != null) { fieldInfo.SetValue(obj, null); } break; } } } //測試代碼 PubFunction.RemoveEvent<BetchSettingValueForm>(this, "BeforeDictEntry"); //特殊幫助類型幫助前過濾擴展 MethodInfo method = valExtend.GetType().GetMethod(field.Element.LabelID + "_Extend"); if (method != null) { valExtend.gspState = GspState; valExtend.dsMXJH = MXJH; //轉化method到delegate Delegate methodDel = PubFunction.CreateDelegateFromMethodInfo<BeforeDictEntryEventArgs<SmartHelpInfo>>(valExtend, method); //先移除事件再註冊 BeforeDictEntry += methodDel as EventHandler<BeforeDictEntryEventArgs<SmartHelpInfo>>; } #endregion //值改變事件註冊,完成批量設置 PubFunction.RemoveEvent<ButtonEdit>(helpEdit, "ButtonClick"); helpEdit.ButtonClick += helpEdit_ButtonClick;
出處:https://blog.csdn.net/soapcoder92/article/details/51027117
======================================================================================================
class Program { static void Main(string[] args) { Customer c = new Customer(); EventInfo evt = c.GetType().GetEvent("OnChange", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public ); // 添加一個事件關聯 evt.AddEventHandler(c, new EventHandler(c_OnChange)); // 添加第二個事件關聯 evt.AddEventHandler(c, new EventHandler(c_OnChange)); // 刪除所有事件關聯。 RemoveEvent<Customer>(c, "OnChange"); c.Change(); } static void c_OnChange(object sender, EventArgs e) { Console.WriteLine("事件被觸發了"); } static void RemoveEvent<T>(T c, string name) { Delegate[] invokeList = GetObjectEventList(c, name); if (invokeList == null) return; foreach (Delegate del in invokeList) { typeof(T).GetEvent(name).RemoveEventHandler(c, del); } } public static Delegate[] GetObjectEventList(object p_Object, string p_EventName) { // Get event field FieldInfo _Field = p_Object.GetType().GetField(p_EventName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static); if (_Field == null) { return null; } // get the value of event field which should be a delegate object _FieldValue = _Field.GetValue(p_Object); // if it is a delegate if (_FieldValue != null && _FieldValue is Delegate) { // cast the value to a delegate Delegate _ObjectDelegate = (Delegate)_FieldValue; // get the invocation list return _ObjectDelegate.GetInvocationList(); } return null; } } class Customer { public event EventHandler OnChange; public void Change() { if (OnChange != null) OnChange(this, null); else Console.WriteLine("no event attached"); } }
出處:https://blog.csdn.net/diandian82/article/details/5738299
參考:https://bbs.csdn.net/topics/370126564
======================================================================================================
根據上面的代碼,我本身通過修改以下:
/// <summary> /// 獲取窗體控件的註冊事件名稱。 /// 例如:按鈕的單擊事件: /// GetObjectEventList<Control>(button1, "Click"); /// 菜單項的單擊事件: /// GetObjectEventList<System.Windows.Forms.ToolStripItem>(menuStrip1.Items[0], "Click"); /// 不一樣的控件的基類也不相同,在使用的時候應格外注意,不然將返回Null /// 另外,我這裏方法內部使用了EventClick的事件記錄,在使用的時候最好仍是調試看看事件名稱是否匹配 /// </summary> /// <typeparam name="T">表示事件所定義的類</typeparam> /// <param name="pControl">控件實例,或事件的子類</param> /// <param name="pEventName">事件名稱</param> /// <returns></returns> private Delegate[] GetObjectEventList<T>(T pControl, string pEventName) { Delegate[] ret = null; Type ctlType = typeof(T); PropertyInfo _PropertyInfo = ctlType.GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic); if (_PropertyInfo != null) { EventHandlerList _EventList = _PropertyInfo.GetValue(pControl, null) as EventHandlerList; FieldInfo _FieldInfo = ctlType.GetField("Event" + pEventName, BindingFlags.Static | BindingFlags.NonPublic); if (_EventList != null && _EventList is EventHandlerList && _FieldInfo != null) { Delegate _ObjectDelegate = _EventList[_FieldInfo.GetValue(pControl)]; if (_ObjectDelegate != null) ret = _ObjectDelegate.GetInvocationList(); } } return ret; }
調用方式:(肯定事件定義的類,如Button在Control中定義的Click事件,否則會找不到事件)
Delegate[] d1 = EventTest.GetObjectEventList<System.Windows.Forms.Control>(btnTest, "Click");
Delegate[] d2 = EventTest.GetObjectEventList<System.Windows.Forms.ToolStripItem>(menuStrip1.Items[0], "Click");
支持自定義類中的自定義事件
public static Delegate[] GetCustomEventList(object obj, string eventName) { Delegate[] ret = null; BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static; EventInfo[] eventInfo = obj.GetType().GetEvents(bindingFlags);//此處獲取全部事件 EventInfo ei = obj.GetType().GetEvent(eventName, bindingFlags); if (ei != null) { FieldInfo _FieldInfo = ei.DeclaringType.GetField(eventName, bindingFlags); Delegate _ObjectDelegate = _FieldInfo.GetValue(obj) as Delegate; ret = _ObjectDelegate?.GetInvocationList(); } return ret; }