如何从事件中删除所有事件处理程序


366

要在控件上创建新的事件处理程序,您可以执行此操作

c.Click += new EventHandler(mainFormButton_Click);

或这个

c.Click += mainFormButton_Click;

并删除事件处理程序,您可以执行此操作

c.Click -= mainFormButton_Click;

但是,如何从事件中删除所有事件处理程序?


10
如果有人来这里寻求WPF解决方案,您可能需要看看这个答案
道格拉斯

1
你不能只是设置c.Click = null吗?
亚历山大

这是我发现过于复杂的事情之一。一个简单的Clear方法显然需要太多的精力
Zimano

Answers:


167

我在MSDN论坛上找到了解决方案。以下示例代码将从中删除所有Click事件button1

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正确处置?
达米安

3
如果我错了,请纠正我,但是不应该以第一行RemoveClickEvent开头FieldInfo f1 = typeof(Button)吗?GetField如果使用,我将得到null Control
保护者

2
这似乎不适用于ToolStripButtons。我已经用ToolStripButton替换了RemoveClickEvent中的Button,但是在调用RemoveClickEvent之后事件仍然存在。有没有人解决这个问题?
Skalli 2011年

1
MSDN中的上述链接还建议尝试使用myButton.Click + = null; 如果要删除所有代表(不是针对Click,而是针对其他事件。)
hello_earth 2013年

1
@hello_earth似乎不适合ObservableCollection.CollectionChanged += null;
Mike de Klerk

146

你们自己对这种方式太难了。这很简单:

void OnFormClosing(object sender, FormClosingEventArgs e)
{
    foreach(Delegate d in FindClicked.GetInvocationList())
    {
        FindClicked -= (FindClickedHandler)d;
    }
}

57
仅当您拥有该活动时,这才起作用。尝试在控件上进行操作。
Delyan

226
...并且如果您拥有该活动,则可以编写FindClicked = null;,这非常简单。
乔恩·斯凯特

79
什么是FindClicked?
Levitikon 2012年

3
这不适用于Kinect事件- kinect.ColorFrameReady -= MyEventHander可以,但是GetInvocationList()kinect实例上没有方法可以迭代其委托。
布伦特·浮士德

GetInvocationList未找到。

75

通过删除所有事件处理程序

直接不,主要是因为您不能简单地将事件设置为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();
}

4
我以为OP是指一般的.net控件。在这种控件中,这种包装可能是不可能的。
Gishu

4
您可以派生控件,那么它将
Tom Fobear 2011年

这还会导致维护两个列表,请参阅stackoverflow.com/questions/91778/…以进行重置,或访问stackoverflow.com/questions/91778/…以访问该列表。
TN。

63

接受的答案不完整。对于声明为{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;
}

4
这个版本对我有用。接受的版本无效。+1。
Meister Schnitzel 2014年

1
直到我BindingFlags.Public在第一个GetField电话中使用过,WPF事件才起作用。
Lennart

40

删除不存在的事件处理程序不会有任何危害。因此,如果您知道可能有什么处理程序,则只需删除所有这些处理程序即可。我只是有类似的情况。在某些情况下这可能会有所帮助。

喜欢:

// Add handlers...
if (something)
{
    c.Click += DoesSomething;
}
else
{
    c.Click += DoesSomethingElse;
}

// Remove handlers...
c.Click -= DoesSomething;
c.Click -= DoesSomethingElse;

16

我实际上正在使用此方法,并且效果很好。Aeonhack 在这里编写的代码给我“启发” 。

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处理。


2
请不要用其他语言写答案。
希勒,

10

我讨厌这里显示的所有完整解决方案,我进行了混合并进行了测试,可用于任何事件处理程序:

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;
        }
    }
}

简单!感谢Stephen Punak。

我之所以使用它,是因为我使用通用的本地方法来删除委托,并且在设置了不同的委托的情况下,在不同情况下调用了本地方法。


4

如果确实需要这样做,则需要进行反思,并且需要花费一些时间。事件处理程序在控件内部的事件到委托映射中进行管理。您需要

  • 在控件实例中反映并获取此映射。
  • 迭代每个事件,获取代表
    • 每个委托人可以依次是一系列事件处理程序。因此调用obControl.RemoveHandler(event,handler)

总之,很多工作。从理论上讲是有可能的...我从未尝试过类似的方法。

查看是否可以更好地控制/约束控件的“订阅-取消订阅”阶段。


3

斯蒂芬有权利。这很简单:

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;
        }
    }
}

38
天哪,编译器应该禁止这种变量名。graphs_must_be_redraw法文。
gracchus

4
翻译自法文 foreach (EventHandler<MyCompletedArgs> handler in CompletionCompleted.GetInvocationList()) { CompletionCompleted -= handler; }
Anton K

@AntonK的英语翻译效果很好。记住要在属性处理程序上检查null。
布雷特

2

我刚刚发现如何在设置WinForms控件的属性时暂停事件。它将删除控件中的所有事件:

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]);
            }
        }

    }
}

1
这非常有帮助,但是需要更改一件事:在Resume()中,您要以相反的顺序添加处理程序(我假设它是来自Suppress的复制/粘贴,您想在其中进行反向操作,所以以免弄乱您正在迭代的集合)。一些代码依赖于处理程序以给定的顺序触发,因此不应对此感到困惑。
迈克尔

1

哇。我找到了这个解决方案,但没有任何工作如我所愿。但这太好了:

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?
迈克尔

1

此页面对我有很大帮助。我从这里获得的代码旨在删除按钮中的click事件。我需要从某些面板中删除双击事件,并从某些按钮中删除单击事件。因此,我做了一个控件扩展,它将删除特定事件的所有事件处理程序。

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));

如果您需要从面板中删除doubleclick事件,

Panel panel = new Panel();
panel.RemoveEvents(nameof(panel.EventDoubleClick));

我不是C#专家,所以如果有任何错误,请原谅我,并请让我知道。


1
.CastTo <>()扩展方法在哪里找到?
IbrarMumtaz

您可以自己编写:public static T CastTo <T>(this object objectToCast){return(T)objectToCast; }
KingOfHypocrites 2012年

0

有时,我们必须使用ThirdParty控件,并且需要构建这些尴尬的解决方案。基于@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");

0

我找到了道格拉斯的另一个可行的解决方案。

此方法将删除在元素上的特定路由事件上设置的所有事件处理程序。
像这样使用

Remove_RoutedEventHandlers(myImage, Image.MouseLeftButtonDownEvent);

完整代码:

/// <summary>
/// Removes all event handlers subscribed to the specified routed event from the specified element.
/// </summary>
/// <param name="element">The UI element on which the routed event is defined.</param>
/// <param name="RoutetEvent_ToRemove">The routed event for which to remove the event handlers.</param>
public static void RemoveRoutedEventHandlers(UIElement UIElement_Target, RoutedEvent RoutetEvent_ToRemove)
{
    // Get the EventHandlersStore instance which holds event handlers for the specified element.
    // The EventHandlersStore class is declared as internal.
    PropertyInfo PropertyInfo_EventHandlersStore = typeof(UIElement).GetProperty(
        "EventHandlersStore", BindingFlags.Instance | BindingFlags.NonPublic);
    object oEventHandlersStore = PropertyInfo_EventHandlersStore.GetValue(UIElement_Target, null);

    // If there's no event handler subscribed, return
    if (oEventHandlersStore == null) return;

    // Invoke the GetRoutedEventHandlers method on the EventHandlersStore instance 
    // for getting an array of the subscribed event handlers.
    MethodInfo MethodInfo_RoutedEventHandlers = oEventHandlersStore.GetType().GetMethod(
        "GetRoutedEventHandlers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
    RoutedEventHandlerInfo[] RoutedEventHandlerInfos = (RoutedEventHandlerInfo[])MethodInfo_RoutedEventHandlers.Invoke(
        oEventHandlersStore, new object[] { RoutetEvent_ToRemove });

    // Iteratively remove all routed event handlers from the element.
    foreach (RoutedEventHandlerInfo RoutedEventHandlerInfo_Tmp in RoutedEventHandlerInfos)
        UIElement_Target.RemoveHandler(RoutetEvent_ToRemove, RoutedEventHandlerInfo_Tmp.Handler);
}

0

删除按钮的所有处理程序:save.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();
    }
}

-1

好吧,这里还有另一种解决方案来删除关联的事件(如果您已经具有处理控件事件的方法):

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);

您只需执行this.button1.MouseDown-= Delegate.CreateDelegate(typeof(EventHandler),此为“ button1_MouseDownClicked”)。因此,这将无助于解决以下问题:如何找出要删除的委托,特别是如果它们是内联的。
Softlion

-1

这不是OP的解决方案,但我想在此发布此信息,以防它可以帮助其他人。

  /// <summary>
  /// Method to remove a (single) SocketAsyncEventArgs.Completed event handler. This is 
  /// partially based on information found here: http://stackoverflow.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);
  }

-3

我找到了这个答案,它几乎可以满足我的需求。感谢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);
                    }
                }
            }
        }
    } 
}

8
这是一个复杂的解决方案,切勿在工业级软件中使用。最佳方法如上所述:妥善管理事件订阅和取消订阅,您将永远不会遇到此类问题。
Tri Q Tran

我同意我们不应该使用反射来解开事件,事件订阅和取消订阅应该由应用程序管理。我认为辩论中的问题应该在调试时使用,以找出我们在讨厌什么。对于要重构的旧版应用程序,这是必须的。
Tiago Freitas Leal 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.