控件的事件清除,除了-=,就只能依靠反射來執行了。
/// <summary> /// 清除一個對象的某個事件所掛鈎的delegate /// </summary> /// <param name="ctrl">控件對象</param> /// <param name="eventName">事件名稱,默認的</param> public static void ClearEvents(this object ctrl, string eventName = "_EventAll") { if (ctrl == null) return; BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Static; EventInfo[] events = ctrl.GetType().GetEvents(bindingFlags); if (events == null || events.Length < 1) return; for (int i = 0; i < events.Length; i++) { try { EventInfo ei = events[i]; //只刪除指定的方法,默認是_EventAll,前面加_是為了和系統的區分,防以后雷同 if (eventName != "_EventAll" && ei.Name != eventName) continue; /******************************************************** * class的每個event都對應了一個同名(變了,前面加了Event前綴)的private的delegate類 * 型成員變量(這點可以用Reflector證實)。因為private成 * 員變量無法在基類中進行修改,所以為了能夠拿到base * class中聲明的事件,要從EventInfo的DeclaringType來獲取 * event對應的成員變量的FieldInfo並進行修改 ********************************************************/ FieldInfo fi = ei.DeclaringType.GetField("Event" + ei.Name, bindingFlags); if (fi != null) { // 將event對應的字段設置成null即可清除所有掛鈎在該event上的delegate fi.SetValue(ctrl, null); } } catch { } } }
當前使用環境.net 4.0。參考了很多其他人的代碼,有三個地方值得注意。
一個是eventName,GetField的時候在原來的Name前面加"Event"前綴。這個可能在不同的.net版本不一樣,出現過三種:eventName,"Event"+eventName, "Event_" + controlType.Name + eventname.
第二個:BindingFlags。盡量用Public | NonPublic | Instance | IgnoreCase | Static。
第三:GetField的執行對象用EventInfo.DeclaringType,否則有可能繼承的類獲取不到數據。
補充一個測試。下面的代碼中Button會執行三次-=然后+=,但是每次的對象都是重新new的。三次綁定后,點擊button1時,只執行一次輸出。
public Form1() { this.Load += (a, b) => { new Thread(new ThreadStart(() => { int i = 0; while (true) { if (button1.InvokeRequired) button1.Invoke(new Action(ReBindEvent)); else ReBindEvent(); Thread.Sleep(100); i++; if (i >= 3) break; } })).Start(); }; } void ReBindEvent() { button1.Click -= GetClickHandle(); button1.Click += GetClickHandle(); } EventHandler GetClickHandle() { return new EventHandler((a, b) => { Console.WriteLine(DateTime.Now + " 執行一次"); }); }