How to remove all event handlers from an event

后端 未结 18 1638
再見小時候
再見小時候 2020-11-22 01:20

To create a new event handler on a control you can do this

c.Click += new EventHandler(mainFormButton_Click);

or this

c.Cli         


        
相关标签:
18条回答
  • 2020-11-22 01:33

    Wow. I found this solution, but nothing worked like I wanted. But this is so good:

    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);
    }
    
    0 讨论(0)
  • 2020-11-22 01:35

    I found this answer and it almost fit my needs. Thanks to SwDevMan81 for the class. I have modified it to allow suppression and resumation of individual methods, and I thought I'd post it here.

    // 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);
                        }
                    }
                }
            }
        } 
    }
    
    0 讨论(0)
  • 2020-11-22 01:36

    From Removing All Event Handlers:

    Directly no, in large part because you cannot simply set the event to null.

    Indirectly, you could make the actual event private and create a property around it that tracks all of the delegates being added/subtracted to it.

    Take the following:

    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();
    }
    
    0 讨论(0)
  • 2020-11-22 01:36

    If you reaallly have to do this... it'll take reflection and quite some time to do this. Event handlers are managed in an event-to-delegate-map inside a control. You would need to

    • Reflect and obtain this map in the control instance.
    • Iterate for each event, get the delegate
      • each delegate in turn could be a chained series of event handlers. So call obControl.RemoveHandler(event, handler)

    In short, a lot of work. It is possible in theory... I never tried something like this.

    See if you can have better control/discipline over the subscribe-unsubscribe phase for the control.

    0 讨论(0)
  • 2020-11-22 01:36

    I found another working solution by Douglas.

    This method removes all event handlers which are set on a specific routet event on a element.
    Use it like

    Remove_RoutedEventHandlers(myImage, Image.MouseLeftButtonDownEvent);
    

    Full code:

    /// <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 讨论(0)
  • 2020-11-22 01:40

    This page helped me a lot. The code I got from here was meant to remove a click event from a button. I need to remove double click events from some panels and click events from some buttons. So I made a control extension, which will remove all event handlers for a certain event.

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

    Now, the usage of this extenstion. If you need to remove click events from a button,

    Button button = new Button();
    button.RemoveEvents(nameof(button.EventClick));
    

    If you need to remove doubleclick events from a panel,

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

    I am not an expert in C#, so if there are any bugs please forgive me and kindly let me know about it.

    0 讨论(0)
提交回复
热议问题