c# remove So entfernen Sie alle Ereignishandler aus einem Ereignis




windows forms event handler (13)

Um einen neuen Event-Handler für ein Steuerelement zu erstellen, können Sie dies tun

c.Click += new EventHandler(mainFormButton_Click);

oder dieses

c.Click += mainFormButton_Click;

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

c.Click -= mainFormButton_Click;

Aber wie entfernen Sie alle Event-Handler von einem Event?


Ich hasste alle hier gezeigten Komplettlösungen, ich machte einen Mix und testete jetzt, arbeitete für jeden Event-Handler:

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

Einfach! Danke für Stephen Punak.

Ich habe es verwendet, weil ich eine generische lokale Methode verwende, um die Delegierten zu entfernen, und die lokale Methode wurde nach verschiedenen Fällen aufgerufen, wenn unterschiedliche Delegaten eingestellt sind.


Vom Entfernen aller Event-Handler :

Direkt Nein, zum großen Teil, weil Sie das Ereignis nicht einfach auf null setzen können.

Indirekt können Sie das tatsächliche Ereignis als "privat" definieren und eine Eigenschaft erstellen, die alle hinzugefügten / subtrahierten Delegierten verfolgt.

Nimm folgendes:

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

Es tut nicht weh, einen nicht vorhandenen Event-Handler zu löschen. Wenn Sie also wissen, welche Handler da sind, können Sie sie einfach löschen. Ich hatte gerade einen ähnlichen Fall. Dies kann in einigen Fällen helfen.

Mögen:

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

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

Ich habe eine Lösung in den MSDN-Foren gefunden . Der folgende Beispielcode entfernt alle Click Ereignisse von 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]);
        }
    }
}

Wenn Sie dies wirklich tun müssen ... wird es einige Zeit dauern um darüber nachzudenken . Ereignishandler werden in einer Event-to-Delegate-Map in einem Steuerelement verwaltet. Das müsstest du tun

  • Reflektieren und erhalten Sie diese Map in der Kontrollinstanz.
  • Iterate für jedes Ereignis, erhalte den Delegierten
    • Jeder Delegierte wiederum könnte eine verkettete Reihe von Ereignisbehandlern sein. Also rufe obControl.RemoveHandler auf (Event, Handler)

Kurz gesagt, viel Arbeit. Es ist theoretisch möglich ... Ich habe sowas nie probiert.

Sehen Sie, ob Sie eine bessere Kontrolle / Disziplin über die Subscribe-Abmeldephase für das Steuerelement haben können.


Dies ist keine Antwort auf das OP, aber ich dachte, ich würde dies hier posten, falls es anderen helfen kann.

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

Beeindruckend. Ich habe diese Lösung gefunden, aber nichts hat so funktioniert, wie ich es 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);
}

Akzeptierte Antwort ist nicht voll. Es funktioniert nicht für Ereignisse, die als {add; Löschen;}

Hier ist Arbeitscode:

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

Nun, hier gibt es eine andere Lösung, um ein assoziiertes Ereignis zu entfernen (wenn Sie bereits eine Methode zur Behandlung der Ereignisse für das Steuerelement haben):

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

Ihr Jungs macht diesen Weg zu hart für euch. Es ist so einfach:

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

Ich benutze tatsächlich diese Methode und es funktioniert perfekt. Ich wurde von dem here von Aeonhack geschriebenen Code "inspiriert".

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

Das Feld MyEventEvent ist ausgeblendet, aber es existiert.

Beim Debuggen können Sie sehen, wie d.target das Objekt ist, das tatsächlich das Ereignis behandelt, und d.method seine Methode. Sie müssen es nur entfernen.

Es funktioniert großartig. Keine weiteren Objekte werden wegen der Event-Handler nicht gecodiert.


Stephen hat Recht. Es ist sehr leicht:

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

Diese Seite hat mir sehr geholfen. Der Code, den ich von hier bekommen habe, sollte ein Klick-Ereignis von einer Schaltfläche entfernen. Ich muss Doppelklickereignisse aus einigen Fenstern entfernen und auf Ereignisse von einigen Tasten klicken. Also habe ich eine Kontrollextension gemacht, die alle Event-Handler für ein bestimmtes Ereignis entfernt.

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 Control target,string Event)
    {
        FieldInfo f1 = typeof(Control).GetField(Event,BindingFlags.Static | BindingFlags.NonPublic);
        object obj = f1.GetValue(target.CastTo<T>());
        PropertyInfo pi = target.CastTo<T>().GetType().GetProperty("Events",
                            BindingFlags.NonPublic | BindingFlags.Instance);
        EventHandlerList list = (EventHandlerList)pi.GetValue(target.CastTo<T>(), null);
        list.RemoveHandler(obj, list[obj]);
    }
}

Jetzt, die Verwendung dieser Erweiterung. Wenn Sie Klickereignisse von einer Schaltfläche entfernen müssen,

Button button = new Button();
button.RemoveEvents<Button>("EventClick");

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

Panel panel = new Panel();
panel.RemoveEvents<Panel>("EventDoubleClick");

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





events