it-swarm-tr.com

Bir olaydaki tüm olay işleyicileri nasıl kaldırılır

Bir kontrolde yeni bir olay işleyicisi oluşturmak için bunu yapabilirsiniz

c.Click += new EventHandler(mainFormButton_Click);

veya bu

c.Click += mainFormButton_Click;

ve bir olay işleyicisi kaldırmak için bunu yapabilirsiniz

c.Click -= mainFormButton_Click;

Ancak tüm etkinlik işleyicilerini bir etkinlikten nasıl kaldırırsınız?

331
Carrick

MSDN forumları üzerinde bir çözüm buldum. Aşağıdaki örnek kod tüm Click olaylarını button1 öğesinden kaldırır.

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

Sizler bu YOL'u kendiniz için çok zorlaştırıyorsunuz. Bu kolay:

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

Kimden Tüm Etkinlik İşleyicilerini Kaldırma:

Doğrudan hayır, büyük kısmı çünkü olayı null değerine ayarlayamazsınız.

Dolaylı olarak, gerçek olayı özel kılabilir ve çevresinde kendisine eklenen/çıkarılan tüm delegelerin izini süren bir özellik yaratabilirsiniz.

Aşağıdakileri alın:

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

Kabul edilen cevap dolu değil. {Add; Kaldır;}

İşte çalışma kodu:

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

Var olmayan bir olay işleyiciyi silmek herhangi bir zarar vermez. Yani, hangi işleyicilerin olabileceğini biliyorsanız, hepsini silebilirsiniz. Ben de benzer bir dava yaşadım. Bu, bazı durumlarda yardımcı olabilir.

Sevmek:

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

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

Aslında bu yöntemi kullanıyorum ve mükemmel çalışıyor. Aeonhack here tarafından yazılan koddan 'ilham aldım'.

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 alanı gizlidir, ancak var.

Hata ayıklama, d.target nesnesinin olayı gerçekten nasıl işlediğini ve d.method yöntemini nasıl gördüğünü görebilirsiniz. Sadece kaldırmak zorundasın.

Harika çalışıyor. Olay işleyicileri nedeniyle artık GC'ed olmamak.

18

Burada gösterilen tüm çözümlerden nefret ettim, şimdi bir karışım yaptım ve test ettim, herhangi bir olay işleyicisi için çalıştım:

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

Kolay! Stephen Punak için teşekkürler.

Delegeleri çıkarmak için genel bir yerel yöntem kullandığım için kullandım ve farklı delegeler belirlendiğinde farklı durumlarda yerel yöntem çağrıldı.

7

Eğer gerçekten bunu yapmak zorundaysanız ... bunun yapılması biraz zaman alacaktır. Olay işleyicileri, bir kontrolün içindeki temsilci olay haritasından yönetilir. İhtiyacınız olacak

  • Kontrol örneğinde bu haritayı yansıtın ve elde edin.
  • Her olay için tekrar edin, temsilciyi alın
    • her bir temsilci sırayla zincirleme bir dizi etkinlik işleyicisi olabilir. Yani obControl.RemoveHandler (olay, işleyici) çağırın

Kısacası, çok iş. Teoride mümkündür ... Asla böyle bir şey denemedim.

Kontrol için abone olma-iptal aşaması üzerinde daha iyi kontrol/disiplin sahibi olup olmadığınızı görün.

5
Gishu

Stephen haklı. Bu çok kolay:

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

Sadece buldum WinForms denetiminin bir özelliğini ayarlarken olayları askıya alma. Tüm olayları bir kontrolden kaldıracak:

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

    }
}
3
SwDevMan81

Bu sayfa bana çok yardımcı oldu. Buradan aldığım kod, bir düğmeden bir click olayını kaldırmak içindir. Bazı panellerden çift tıklatma olaylarını kaldırmam ve bazı düğmelerden olayları tıklamam gerekiyor. Bu nedenle, belirli bir olay için tüm olay işleyicilerini kaldıracak bir kontrol uzantısı yaptım.

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

Şimdi, bu uzatma kullanımı. Bir düğmeden tıklama olaylarını kaldırmanız gerekirse,

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

İki kat olaylarını bir panelden kaldırmanız gerekirse,

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

C # konusunda uzman değilim, bu yüzden herhangi bir hata varsa lütfen beni affedin ve lütfen bana bildirin.

2

Vay. Bu çözümü buldum ama hiçbir şey istediğim gibi çalışmadı. Ama bu çok iyi:

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);
}
2
Sergio Cabral

Bazen ThirdParty kontrolleri ile çalışmak zorundayız ve bu garip çözümleri üretmemiz gerekiyor. @Anoop Muraleedharan cevabına dayanarak Bu çözümü çıkarım tipi ve ToolStripItem desteği ile oluşturdum

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

Ve bu şekilde kullanabilirsiniz

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

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

Bu OP'ye bir cevap değil, ama başkalarına yardım etmesi için bunu buraya göndereceğimi düşündüm.

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