如何从事件中删除所有事件处理程序
Posted
技术标签:
【中文标题】如何从事件中删除所有事件处理程序【英文标题】:How to remove all event handlers from an event 【发布时间】:2010-09-10 15:27:56 【问题描述】:要在控件上创建新的事件处理程序,您可以这样做
c.Click += new EventHandler(mainFormButton_Click);
或者这个
c.Click += mainFormButton_Click;
要删除事件处理程序,您可以这样做
c.Click -= mainFormButton_Click;
但是?
【问题讨论】:
如果有人来这里寻找 WPF 解决方案,您可能需要查看this answer。 你不能只设置c.Click = null
吗?
这是我觉得过于复杂的事情之一。一个简单的Clear
方法显然太费劲了
在 .NET 4.5 中,如果 List.Count > 2 可以说,并且您尝试删除第一个委托 InvocatorList[0] == mainFormButton_Click... 就像您所做的那样......它将删除所有其中。我认为这是一个错误!
【参考方案1】:
我在MSDN forums 上找到了解决方案。下面的示例代码将从button1
中删除所有Click
事件。
public partial class Form1 : Form
public Form1()
InitializeComponent();
button1.Click += button1_Click;
button1.Click += button1_Click2;
button2.Click += button2_Click;
private void button1_Click(object sender, EventArgs e) => MessageBox.Show("Hello");
private void button1_Click2(object sender, EventArgs e) => MessageBox.Show("World");
private void button2_Click(object sender, EventArgs e) => RemoveClickEvent(button1);
private void RemoveClickEvent(Button b)
FieldInfo f1 = typeof(Control).GetField("EventClick",
BindingFlags.Static | BindingFlags.NonPublic);
object obj = f1.GetValue(b);
PropertyInfo pi = b.GetType().GetProperty("Events",
BindingFlags.NonPublic | BindingFlags.Instance);
EventHandlerList list = (EventHandlerList)pi.GetValue(b, null);
list.RemoveHandler(obj, list[obj]);
【讨论】:
如果 button1 设置为 null,是否所有附加到 button1.Click 的事件处理程序都正确处理? 如果我错了,请纠正我,但RemoveClickEvent
的第一行不应该以:FieldInfo f1 = typeof(Button)
开头吗?如果我使用Control
,我会从GetField
得到空值。
这似乎不适用于 ToolStripButtons。我已将 RemoveClickEvent 中的 Button 替换为 ToolStripButton,但在调用 RemoveClickEvent 后事件仍然存在。有没有人解决这个问题?
MSDN 中的上述链接也建议尝试 myButton.Click += null;如果要删除所有代表(不是针对 Click,而是针对其他事件..)
@hello_earth 似乎不适用于ObservableCollection.CollectionChanged += null;
【参考方案2】:
你们对自己太苛刻了。就这么简单:
void OnFormClosing(object sender, FormClosingEventArgs e)
foreach(Delegate d in FindClicked.GetInvocationList())
FindClicked -= (FindClickedHandler)d;
【讨论】:
这只有在您拥有该事件时才有效。尝试在控件上执行此操作。 ...如果您拥有该活动,您可以只写FindClicked = null;
,这样比较简单。
这对 Kinect 事件不起作用 -- kinect.ColorFrameReady -= MyEventHander
可以,但在 kinect 实例上没有 GetInvocationList()
方法来迭代其委托。
GetInvocationList
未找到。
@Timo:对,它必须是那个确切的类。【参考方案3】:
来自Removing All Event Handlers:
直接不,很大程度上是因为你 不能简单地将事件设置为 null。
间接地,你可以做实际的 事件私有并创建一个属性 在它周围追踪所有 代表被添加/减去 它。
采取以下措施:
List<EventHandler> delegates = new List<EventHandler>(); private event EventHandler MyRealEvent; public event EventHandler MyEvent add MyRealEvent += value; delegates.Add(value); remove MyRealEvent -= value; delegates.Remove(value); public void RemoveAllEvents() foreach(EventHandler eh in delegates) MyRealEvent -= eh; delegates.Clear();
【讨论】:
我认为 OP 指的是一般的 .net 控件。在这种情况下,这种包装可能是不可能的。 你可以派生控件,然后它会 这也导致维护两个列表,请参阅***.com/questions/91778/… 重置或***.com/questions/91778/… 访问列表。 遗憾的是,我不能将此行为包装在接口上,因为它不能有实例字段。 @Noman_1 - 当您想要一个字段时,wlith 接口解决方案是使用一对方法(getter/setter)。然后由每个类来实现该方法对。【参考方案4】:接受的答案不完整。它不适用于声明为 add; 的事件。删除;
这是工作代码:
public static void ClearEventInvocations(this object obj, string eventName)
var fi = obj.GetType().GetEventField(eventName);
if (fi == null) return;
fi.SetValue(obj, null);
private static FieldInfo GetEventField(this Type type, string eventName)
FieldInfo field = null;
while (type != null)
/* Find events defined as field */
field = type.GetField(eventName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic);
if (field != null && (field.FieldType == typeof(MulticastDelegate) || field.FieldType.IsSubclassOf(typeof(MulticastDelegate))))
break;
/* Find events defined as property add; remove; */
field = type.GetField("EVENT_" + eventName.ToUpper(), BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic);
if (field != null)
break;
type = type.BaseType;
return field;
【讨论】:
这个版本对我有用。接受的版本不起作用。为此 +1。 直到我在第一个GetField
调用中使用 BindingFlags.Public
之前,它不适用于 WPF 事件。【参考方案5】:
删除不存在的事件处理程序没有任何害处。因此,如果您知道可能有哪些处理程序,您可以简单地删除所有处理程序。我刚遇到类似的情况。这在某些情况下可能会有所帮助。
喜欢:
// Add handlers...
if (something)
c.Click += DoesSomething;
else
c.Click += DoesSomethingElse;
// Remove handlers...
c.Click -= DoesSomething;
c.Click -= DoesSomethingElse;
【讨论】:
是的,但问题是您可以多次执行 +=,然后无法知道有多少相同的事件附加到处理程序。所以你不知道有多少-=你需要一路清除。【参考方案6】:我讨厌这里显示的任何完整解决方案,我现在做了混合和测试,适用于任何事件处理程序:
public class MyMain()
public void MyMethod()
AnotherClass.TheEventHandler += DoSomeThing;
private void DoSomething(object sender, EventArgs e)
Debug.WriteLine("I did something");
AnotherClass.ClearAllDelegatesOfTheEventHandler();
public static class AnotherClass
public static event EventHandler TheEventHandler;
public static void ClearAllDelegatesOfTheEventHandler()
foreach (Delegate d in TheEventHandler.GetInvocationList())
TheEventHandler -= (EventHandler)d;
简单!感谢斯蒂芬·普纳克。
我使用它是因为我使用通用的本地方法来删除委托,并且在设置不同的委托时,在不同的情况下调用本地方法。
【讨论】:
【参考方案7】:我实际上正在使用这种方法,并且效果很好。我受到 Aeonhack here 编写的代码的“启发”。
Public Event MyEvent()
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If MyEventEvent IsNot Nothing Then
For Each d In MyEventEvent.GetInvocationList ' If this throws an exception, try using .ToArray
RemoveHandler MyEvent, d
Next
End If
End Sub
字段 MyEventEvent 是隐藏的,但确实存在。
调试,可以看到d.target
是如何实际处理事件的对象,d.method
是它的方法。您只需将其删除即可。
效果很好。由于事件处理程序,没有更多的对象没有被 GC'ed。
【讨论】:
请不要用其他语言写答案。 我不同意 - 这是一个 .NET 问题和问题。 VB.NET 与解决此问题的任何其他 .NET 语言一样有效。我也会包含一个 C# 示例,因为它更常见,但偶尔看到一些 vb.net 仍然很高兴!【参考方案8】:如果您真的必须这样做……这需要反思和相当长的时间。事件处理程序在控件内的事件到委托映射中进行管理。你需要
在控件实例中反映并获取此映射。 迭代每个事件,获取委托 每个委托又可以是一系列链接的事件处理程序。所以调用 obControl.RemoveHandler(event, handler)简而言之,工作量很大。理论上是可能的……我从来没有尝试过这样的事情。
看看您是否可以更好地控制/约束控件的订阅-取消订阅阶段。
【讨论】:
【参考方案9】:斯蒂芬是对的。这很容易:
public event EventHandler<Cles_graph_doivent_etre_redessines> les_graph_doivent_etre_redessines;
public void remove_event()
if (this.les_graph_doivent_etre_redessines != null)
foreach (EventHandler<Cles_graph_doivent_etre_redessines> F_les_graph_doivent_etre_redessines in this.les_graph_doivent_etre_redessines.GetInvocationList())
this.les_graph_doivent_etre_redessines -= F_les_graph_doivent_etre_redessines;
【讨论】:
天哪,编译器应该禁止这种变量名。 graphs_must_be_redrawn 法语。 从法语翻译foreach (EventHandler<MyCompletedArgs> handler in CompletionCompleted.GetInvocationList())
CompletionCompleted -= handler;
@AntonK 的英文翻译效果很好。请记住在属性处理程序上检查 null。【参考方案10】:
我刚刚找到How to suspend events when setting a property of a WinForms control。它将从控件中删除所有事件:
namespace CMessWin05
public class EventSuppressor
Control _source;
EventHandlerList _sourceEventHandlerList;
FieldInfo _headFI;
Dictionary<object, Delegate[]> _handlers;
PropertyInfo _sourceEventsInfo;
Type _eventHandlerListType;
Type _sourceType;
public EventSuppressor(Control control)
if (control == null)
throw new ArgumentNullException("control", "An instance of a control must be provided.");
_source = control;
_sourceType = _source.GetType();
_sourceEventsInfo = _sourceType.GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic);
_sourceEventHandlerList = (EventHandlerList)_sourceEventsInfo.GetValue(_source, null);
_eventHandlerListType = _sourceEventHandlerList.GetType();
_headFI = _eventHandlerListType.GetField("head", BindingFlags.Instance | BindingFlags.NonPublic);
private void BuildList()
_handlers = new Dictionary<object, Delegate[]>();
object head = _headFI.GetValue(_sourceEventHandlerList);
if (head != null)
Type listEntryType = head.GetType();
FieldInfo delegateFI = listEntryType.GetField("handler", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo keyFI = listEntryType.GetField("key", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo nextFI = listEntryType.GetField("next", BindingFlags.Instance | BindingFlags.NonPublic);
BuildListWalk(head, delegateFI, keyFI, nextFI);
private void BuildListWalk(object entry, FieldInfo delegateFI, FieldInfo keyFI, FieldInfo nextFI)
if (entry != null)
Delegate dele = (Delegate)delegateFI.GetValue(entry);
object key = keyFI.GetValue(entry);
object next = nextFI.GetValue(entry);
Delegate[] listeners = dele.GetInvocationList();
if(listeners != null && listeners.Length > 0)
_handlers.Add(key, listeners);
if (next != null)
BuildListWalk(next, delegateFI, keyFI, nextFI);
public void Resume()
if (_handlers == null)
throw new ApplicationException("Events have not been suppressed.");
foreach (KeyValuePair<object, Delegate[]> pair in _handlers)
for (int x = 0; x < pair.Value.Length; x++)
_sourceEventHandlerList.AddHandler(pair.Key, pair.Value[x]);
_handlers = null;
public void Suppress()
if (_handlers != null)
throw new ApplicationException("Events are already being suppressed.");
BuildList();
foreach (KeyValuePair<object, Delegate[]> pair in _handlers)
for (int x = pair.Value.Length - 1; x >= 0; x--)
_sourceEventHandlerList.RemoveHandler(pair.Key, pair.Value[x]);
【讨论】:
这很有帮助,但有一点需要更改:在 Resume() 中,您正在以相反的顺序添加处理程序(我假设它是来自 Suppress 的复制/粘贴,你想向后工作,以免弄乱你正在迭代的集合)。一些代码依赖于按给定顺序触发的处理程序,所以不应该乱用它。【参考方案11】:哇。我找到了这个解决方案,但没有像我想要的那样工作。但这太好了:
EventHandlerList listaEventos;
private void btnDetach_Click(object sender, EventArgs e)
listaEventos = DetachEvents(comboBox1);
private void btnAttach_Click(object sender, EventArgs e)
AttachEvents(comboBox1, listaEventos);
public EventHandlerList DetachEvents(Component obj)
object objNew = obj.GetType().GetConstructor(new Type[] ).Invoke(new object[] );
PropertyInfo propEvents = obj.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
EventHandlerList eventHandlerList_obj = (EventHandlerList)propEvents.GetValue(obj, null);
EventHandlerList eventHandlerList_objNew = (EventHandlerList)propEvents.GetValue(objNew, null);
eventHandlerList_objNew.AddHandlers(eventHandlerList_obj);
eventHandlerList_obj.Dispose();
return eventHandlerList_objNew;
public void AttachEvents(Component obj, EventHandlerList eventos)
PropertyInfo propEvents = obj.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
EventHandlerList eventHandlerList_obj = (EventHandlerList)propEvents.GetValue(obj, null);
eventHandlerList_obj.AddHandlers(eventos);
【讨论】:
这肯定比以前的答案更整洁。它做同样的事情吗?看起来确实如此,但也许我错过了一些东西。另外,当你想要的只是一个 EventHandlerList 时,为什么还要创建一个新对象? EventHandlerList 是否没有可访问的 c-tor,因此只能获取为 Component 内部构造的 c-tor?【参考方案12】:这个页面对我帮助很大。我从这里获得的代码旨在从按钮中删除单击事件。我需要从某些面板中删除双击事件并从某些按钮中删除单击事件。所以我做了一个控制扩展,它将删除某个事件的所有事件处理程序。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Reflection;
public static class EventExtension
public static void RemoveEvents<T>(this T target, string eventName) where T:Control
if (ReferenceEquals(target, null)) throw new NullReferenceException("Argument \"target\" may not be null.");
FieldInfo fieldInfo = typeof(Control).GetField(eventName, BindingFlags.Static | BindingFlags.NonPublic);
if (ReferenceEquals(fieldInfo, null)) throw new ArgumentException(
string.Concat("The control ", typeof(T).Name, " does not have a property with the name \"", eventName, "\""), nameof(eventName));
object eventInstance = fieldInfo.GetValue(target);
PropertyInfo propInfo = typeof(T).GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
EventHandlerList list = (EventHandlerList)propInfo.GetValue(target, null);
list.RemoveHandler(eventInstance, list[eventInstance]);
现在,这个扩展的用法。 如果您需要从按钮中移除点击事件,
Button button = new Button();
button.RemoveEvents(nameof(button.EventClick));
如果您需要从面板中移除双击事件,
Panel panel = new Panel();
panel.RemoveEvents(nameof(panel.EventDoubleClick));
我不是 C# 方面的专家,所以如果有任何错误,请原谅我并请告诉我。
【讨论】:
.CastTo() 扩展方法到底在哪里找到的? 你可以自己写: public static T CastTo聚会有点晚了,但我使用了这个对我来说效果很好的链接: https://www.codeproject.com/Articles/103542/Removing-Event-Handlers-using-Reflection
此代码的美妙之处在于它适用于所有人,WFP、Forms、Xamarin Forms。我将它用于 Xamarin。请注意,仅当您不拥有此事件时才需要这种使用反射的方式(例如,在您不关心的某些事件上崩溃的库代码)。
这是我稍作修改的代码:
static Dictionary<Type, List<FieldInfo>> dicEventFieldInfos = new Dictionary<Type, List<FieldInfo>>();
static BindingFlags AllBindings
get return BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
static void BuildEventFields(Type t, List<FieldInfo> lst)
foreach (EventInfo ei in t.GetEvents(AllBindings))
Type dt = ei.DeclaringType;
FieldInfo fi = dt.GetField(ei.Name, AllBindings);
if (fi != null)
lst.Add(fi);
static List<FieldInfo> GetTypeEventFields(Type t)
if (dicEventFieldInfos.ContainsKey(t))
return dicEventFieldInfos[t];
List<FieldInfo> lst = new List<FieldInfo>();
BuildEventFields(t, lst);
dicEventFieldInfos.Add(t, lst);
return lst;
static EventHandlerList GetStaticEventHandlerList(Type t, object obj)
MethodInfo mi = t.GetMethod("get_Events", AllBindings);
return (EventHandlerList)mi.Invoke(obj, new object[] );
public static void RemoveEventHandler(object obj, string EventName = "")
if (obj == null)
return;
Type t = obj.GetType();
List<FieldInfo> event_fields = GetTypeEventFields(t);
EventHandlerList static_event_handlers = null;
foreach (FieldInfo fi in event_fields)
if (EventName != "" && string.Compare(EventName, fi.Name, true) != 0)
continue;
var eventName = fi.Name;
// After hours and hours of research and trial and error, it turns out that
// STATIC Events have to be treated differently from INSTANCE Events...
if (fi.IsStatic)
// STATIC EVENT
if (static_event_handlers == null)
static_event_handlers = GetStaticEventHandlerList(t, obj);
object idx = fi.GetValue(obj);
Delegate eh = static_event_handlers[idx];
if (eh == null)
continue;
Delegate[] dels = eh.GetInvocationList();
if (dels == null)
continue;
EventInfo ei = t.GetEvent(eventName, AllBindings);
foreach (Delegate del in dels)
ei.RemoveEventHandler(obj, del);
else
// INSTANCE EVENT
EventInfo ei = t.GetEvent(eventName, AllBindings);
if (ei != null)
object val = fi.GetValue(obj);
Delegate mdel = (val as Delegate);
if (mdel != null)
foreach (Delegate del in mdel.GetInvocationList())
ei.RemoveEventHandler(obj, del);
示例用法:RemoveEventHandler(obj, "Focused");
【讨论】:
【参考方案14】:有时我们必须使用第三方控件,并且我们需要构建这些笨拙的解决方案。基于@Anoop Muraleedharan 的回答,我创建了这个具有推理类型和 ToolStripItem 支持的解决方案
public static void RemoveItemEvents<T>(this T target, string eventName)
where T : ToolStripItem
RemoveObjectEvents<T>(target, eventName);
public static void RemoveControlEvents<T>(this T target, string eventName)
where T : Control
RemoveObjectEvents<T>(target, eventName);
private static void RemoveObjectEvents<T>(T target, string Event) where T : class
var typeOfT = typeof(T);
var fieldInfo = typeOfT.BaseType.GetField(
Event, BindingFlags.Static | BindingFlags.NonPublic);
var provertyValue = fieldInfo.GetValue(target);
var propertyInfo = typeOfT.GetProperty(
"Events", BindingFlags.NonPublic | BindingFlags.Instance);
var eventHandlerList = (EventHandlerList)propertyInfo.GetValue(target, null);
eventHandlerList.RemoveHandler(provertyValue, eventHandlerList[provertyValue]);
你可以这样使用它
var toolStripButton = new ToolStripButton();
toolStripButton.RemoveItemEvents("EventClick");
var button = new Button();
button.RemoveControlEvents("EventClick");
【讨论】:
【参考方案15】:删除按钮的所有处理程序: 保存.RemoveEvents();
public static class EventExtension
public static void RemoveEvents<T>(this T target) where T : Control
var propInfo = typeof(T).GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
var list = (EventHandlerList)propInfo.GetValue(target, null);
list.Dispose();
【讨论】:
【参考方案16】:好吧,这里有另一个解决方案来删除关联事件(如果您已经有处理控件事件的方法):
EventDescriptor ed = TypeDescriptor.GetEvents(this.button1).Find("MouseDown",true);
Delegate delegate = Delegate.CreateDelegate(typeof(EventHandler), this, "button1_MouseDownClicked");
if(ed!=null)
ed.RemoveEventHandler(this.button1, delegate);
【讨论】:
你可以这样做。button1.MouseDown -= Delegate.CreateDelegate(typeof(EventHandler), this, "button1_MouseDownClicked")。因此,它无助于解决如何找出要删除的委托的问题,尤其是如果它们是内联的。【参考方案17】:这不是对 OP 的回答,但我想我会在这里发布它以防它可以帮助其他人。
/// <summary>
/// Method to remove a (single) SocketAsyncEventArgs.Completed event handler. This is
/// partially based on information found here: http://***.com/a/91853/253938
///
/// But note that this may not be a good idea, being very .Net implementation-dependent. Note
/// in particular use of "m_Completed" instead of "Completed".
/// </summary>
private static void RemoveCompletedEventHandler(SocketAsyncEventArgs eventArgs)
FieldInfo fieldInfo = typeof(SocketAsyncEventArgs).GetField("m_Completed",
BindingFlags.Instance | BindingFlags.NonPublic);
eventArgs.Completed -= (EventHandler<SocketAsyncEventArgs>)fieldInfo.GetValue(eventArgs);
【讨论】:
【参考方案18】:我找到了这个答案,它几乎符合我的需求。感谢 SwDevMan81 的课程。我已经对其进行了修改以允许抑制和恢复个别方法,我想我会在这里发布。
// This class allows you to selectively suppress event handlers for controls. You instantiate
// the suppressor object with the control, and after that you can use it to suppress all events
// or a single event. If you try to suppress an event which has already been suppressed
// it will be ignored. Same with resuming; you can resume all events which were suppressed,
// or a single one. If you try to resume an un-suppressed event handler, it will be ignored.
//cEventSuppressor _supButton1 = null;
//private cEventSuppressor SupButton1
// get
// if (_supButton1 == null)
// _supButton1 = new cEventSuppressor(this.button1);
//
// return _supButton1;
//
//
//private void button1_Click(object sender, EventArgs e)
// MessageBox.Show("Clicked!");
//
//private void button2_Click(object sender, EventArgs e)
// SupButton1.Suppress("button1_Click");
//
//private void button3_Click(object sender, EventArgs e)
// SupButton1.Resume("button1_Click");
//
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Windows.Forms;
using System.ComponentModel;
namespace Crystal.Utilities
public class cEventSuppressor
Control _source;
EventHandlerList _sourceEventHandlerList;
FieldInfo _headFI;
Dictionary<object, Delegate[]> suppressedHandlers = new Dictionary<object, Delegate[]>();
PropertyInfo _sourceEventsInfo;
Type _eventHandlerListType;
Type _sourceType;
public cEventSuppressor(Control control)
if (control == null)
throw new ArgumentNullException("control", "An instance of a control must be provided.");
_source = control;
_sourceType = _source.GetType();
_sourceEventsInfo = _sourceType.GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic);
_sourceEventHandlerList = (EventHandlerList)_sourceEventsInfo.GetValue(_source, null);
_eventHandlerListType = _sourceEventHandlerList.GetType();
_headFI = _eventHandlerListType.GetField("head", BindingFlags.Instance | BindingFlags.NonPublic);
private Dictionary<object, Delegate[]> BuildList()
Dictionary<object, Delegate[]> retval = new Dictionary<object, Delegate[]>();
object head = _headFI.GetValue(_sourceEventHandlerList);
if (head != null)
Type listEntryType = head.GetType();
FieldInfo delegateFI = listEntryType.GetField("handler", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo keyFI = listEntryType.GetField("key", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo nextFI = listEntryType.GetField("next", BindingFlags.Instance | BindingFlags.NonPublic);
retval = BuildListWalk(retval, head, delegateFI, keyFI, nextFI);
return retval;
private Dictionary<object, Delegate[]> BuildListWalk(Dictionary<object, Delegate[]> dict,
object entry, FieldInfo delegateFI, FieldInfo keyFI, FieldInfo nextFI)
if (entry != null)
Delegate dele = (Delegate)delegateFI.GetValue(entry);
object key = keyFI.GetValue(entry);
object next = nextFI.GetValue(entry);
if (dele != null)
Delegate[] listeners = dele.GetInvocationList();
if (listeners != null && listeners.Length > 0)
dict.Add(key, listeners);
if (next != null)
dict = BuildListWalk(dict, next, delegateFI, keyFI, nextFI);
return dict;
public void Resume()
public void Resume(string pMethodName)
//if (_handlers == null)
// throw new ApplicationException("Events have not been suppressed.");
Dictionary<object, Delegate[]> toRemove = new Dictionary<object, Delegate[]>();
// goes through all handlers which have been suppressed. If we are resuming,
// all handlers, or if we find the matching handler, add it back to the
// control's event handlers
foreach (KeyValuePair<object, Delegate[]> pair in suppressedHandlers)
for (int x = 0; x < pair.Value.Length; x++)
string methodName = pair.Value[x].Method.Name;
if (pMethodName == null || methodName.Equals(pMethodName))
_sourceEventHandlerList.AddHandler(pair.Key, pair.Value[x]);
toRemove.Add(pair.Key, pair.Value);
// remove all un-suppressed handlers from the list of suppressed handlers
foreach (KeyValuePair<object, Delegate[]> pair in toRemove)
for (int x = 0; x < pair.Value.Length; x++)
suppressedHandlers.Remove(pair.Key);
//_handlers = null;
public void Suppress()
Suppress(null);
public void Suppress(string pMethodName)
//if (_handlers != null)
// throw new ApplicationException("Events are already being suppressed.");
Dictionary<object, Delegate[]> dict = BuildList();
foreach (KeyValuePair<object, Delegate[]> pair in dict)
for (int x = pair.Value.Length - 1; x >= 0; x--)
//MethodInfo mi = pair.Value[x].Method;
//string s1 = mi.Name; // name of the method
//object o = pair.Value[x].Target;
// can use this to invoke method pair.Value[x].DynamicInvoke
string methodName = pair.Value[x].Method.Name;
if (pMethodName == null || methodName.Equals(pMethodName))
_sourceEventHandlerList.RemoveHandler(pair.Key, pair.Value[x]);
suppressedHandlers.Add(pair.Key, pair.Value);
【讨论】:
这是一个复杂的解决方案,绝不应该在工业级软件中使用。如前所述,最好的方法是:管理好您的活动订阅和取消订阅,您将永远不会遇到此类问题。 我同意我们不应该使用反射来取消连接事件,并且事件订阅和取消订阅应该由应用程序管理。我认为辩论中的问题应该在 DEBUG 时使用,以找出我们是否在做某事。对于您正在重构的遗留应用程序,这是必须的。以上是关于如何从事件中删除所有事件处理程序的主要内容,如果未能解决你的问题,请参考以下文章