首页 文章

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

提问于
浏览
317

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

c.Click += new EventHandler(mainFormButton_Click);

或这个

c.Click += mainFormButton_Click;

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

c.Click -= mainFormButton_Click;

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

16 回答

  • -3

    我通过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 .

  • 153

    你们这些方式太过刻板了 . 就这么简单:

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

    删除不存在的事件处理程序没有任何损害 . 因此,如果你知道可能有哪些处理程序,你可以简单地删除它们 . 我只是有类似的情况 . 在某些情况下这可能有所帮助 .

    喜欢:

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

    Removing All Event Handlers

    直接不,很大程度上是因为你不能简单地将事件设置为null . 间接地,您可以将实际事件设为私有,并在其周围创建一个属性,以跟踪添加/减去的所有代理 . 请执行以下操作:List <EventHandler> delegates = new List <EventHandler>();

    私人活动EventHandler MyRealEvent;

    公共事件EventHandler MyEvent
    {

    {
    MyRealEvent = value;
    delegates.Add(值);
    }

    去掉
    {
    MyRealEvent - =值;
    delegates.Remove(值);
    }
    }

    public void RemoveAllEvents()
    {
    foreach(EventHandler呃代表)
    {
    MyRealEvent - =呃;
    }
    delegates.Clear();
    }

  • 0

    如果你必须这样做......它需要反思并且需要相当长的时间才能做到这一点 . 事件处理程序在控件内的事件到委托映射中进行管理 . 你需要

    • 在控件实例中反映并获取此映射 .

    • 为每个事件迭代,获得代表

    • 每个代表反过来可以是一系列链式事件处理程序 . 所以调用obControl.RemoveHandler(event,handler)

    总之,做了很多工作 . 理论上可能......我从未尝试过这样的事情 .

    看看你是否可以在控件的subscribe-unsubscribe阶段有更好的控制/纪律 .

  • 0

    哇 . 我找到了这个解决方案,但没有像我想要的那样工作 . 但这太好了:

    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);
    }
    
  • -1

    有时我们必须使用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");
    
  • 66

    我在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]);
            }
        }
    }
    
  • 33

    我找到了这个答案,它几乎符合我的需要 . 感谢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);
                        }
                    }
                }
            }
        } 
    }
    
  • 18

    好吧,这里有另一个解决方案来删除一个相关的事件(如果你已经有一个方法来处理控件的事件):

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

    我刚发现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]);
                }
            }
    
        }
    }
    
  • 4

    我讨厌这里显示的任何完整的解决方案,我做了混合并现在测试,适用于任何事件处理程序:

    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 .

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

  • 3

    接受的答案不完整 . 它不适用于声明为{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

    斯蒂芬说得对 . 这很容易:

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

    这页帮助了我很多 . 我从这里得到的代码意味着从按钮中删除点击事件 . 我需要从某些面板中删除双击事件,然后单击某些按钮中的事件 . 所以我做了一个控件扩展,它将删除某个事件的所有事件处理程序 .

    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#的专家,所以如果有任何错误请原谅我,请让我知道 .

  • 116

    这不是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);
      }
    

相关问题