441 Stimmen

So entfernen Sie alle Ereignisbehandler aus einem Ereignis

Um einen neuen Ereignishandler für ein Steuerelement zu erstellen, können Sie wie folgt vorgehen

c.Click += new EventHandler(mainFormButton_Click);

oder dies

c.Click += mainFormButton_Click;

und um einen Event-Handler zu entfernen, können Sie Folgendes tun

c.Click -= mainFormButton_Click;

Aber wie entfernt man alle Ereignisbehandler aus einem Ereignis?

2voto

Diese Seite hat mir sehr geholfen. Der Code, den ich von hier bekam, war gemeint, um ein Klick-Ereignis von einer Schaltfläche zu entfernen. Ich muss Doppelklick-Ereignisse von einigen Panels und Klick-Ereignisse von einigen Schaltflächen entfernen. Also habe ich eine Steuerelement-Erweiterung, die alle Event-Handler für ein bestimmtes Ereignis entfernen wird.

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

Nun zur Verwendung dieser Erweiterung. Wenn Sie Klick-Ereignisse von einer Schaltfläche entfernen müssen,

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

Wenn Sie Doppelklick-Ereignisse aus einem Panel entfernen müssen,

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

Ich bin kein Experte in C#, wenn es also irgendwelche Fehler gibt, verzeihen Sie mir bitte und lassen Sie es mich bitte wissen.

1voto

Sergio Cabral Punkte 5472

Wow. Ich habe diese Lösung gefunden, aber nichts hat so funktioniert, wie ich wollte. Aber das ist so gut:

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

1voto

Vassili Punkte 141

Ich bin ein bisschen spät dran, aber ich habe diesen Link benutzt, der für mich sehr gut funktioniert hat: https://www.codeproject.com/Articles/103542/Removing-Event-Handlers-using-Reflection

Das Schöne an diesem Code ist, dass er für alle funktioniert, WFP, Forms, Xamarin Forms. Ich habe es für Xamarin verwendet. Beachten Sie, dass Sie diese Art der Verwendung von Reflection nur benötigen, wenn Sie dieses Ereignis nicht besitzen (z. B. ein Bibliothekscode, der bei einem Ereignis abstürzt, das Sie nicht interessiert).

Hier ist mein leicht veränderter Code:

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

Beispiel für die Verwendung: RemoveEventHandler(obj, "Focused");

0voto

Jhonattan Punkte 492

Manchmal müssen wir mit Kontrollen von Drittanbietern arbeiten und müssen diese umständlichen Lösungen entwickeln. Basierend auf der Antwort von @Anoop Muraleedharan habe ich diese Lösung mit Inferenztyp und ToolStripItem-Unterstützung erstellt

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

Und so können Sie es verwenden

    var toolStripButton = new ToolStripButton();
    toolStripButton.RemoveItemEvents("EventClick");

    var button = new Button();
    button.RemoveControlEvents("EventClick");

0voto

Anatoliy Punkte 77

Entfernt alle Handler für die Schaltfläche: 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();
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X