Bir olaydan tüm olay işleyicileri kaldırma


366

Bir denetimde yeni bir olay işleyici oluşturmak için bunu yapabilirsiniz

c.Click += new EventHandler(mainFormButton_Click);

veya bu

c.Click += mainFormButton_Click;

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

c.Click -= mainFormButton_Click;

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


10
Buraya bir WPF çözümü arayan biri varsa, bu cevaba bakmak isteyebilirsiniz .
Douglas

1
Sadece kuramaz c.Click = nullmısın?
alexania

Bu gülünç derecede karmaşık bulduğum şeylerden biri. Basit bir Clearyöntem, görünüşe göre çok fazla çaba oldu
Zimano

Yanıtlar:


167

MSDN forumlarında bir çözüm buldum . Aşağıdaki örnek koddaki tüm Clicketkinlikler kaldırılacak 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]);
        }
    }
}

Button1 null değerine ayarlanırsa, tüm olay işleyicileri button1'e eklenir mi?
Damien

3
Yanılıyorsam düzelt ama olmamalı ilk satırı RemoveClickEventile başlamasından: FieldInfo f1 = typeof(Button)? Ben gelen null adlı almak GetFieldkullandığım eğer Control.
Koruyucu bir

2
Bu, ToolStripButtons için çalışmıyor gibi görünüyor. RemoveClickEvent içinde Button ToolStripButton ile değiştirdim, ancak RemoveClickEvent çağrıldıktan sonra olaylar hala yerinde. Bu sorunun çözümü olan var mı?
Skalli

1
MSDN'deki yukarıdaki bağlantı da myButton.Click + = null; tüm delegeleri kaldırmak istiyorsanız (Tıklama için değil, diğer etkinlikler için ..)
hello_earth

1
@hello_earth Çalışmıyor gibi görünüyorObservableCollection.CollectionChanged += null;
Mike de Klerk

146

Sizler bu YOL'u kendinize çok zorluyorsunuz. Bu kadar kolay:

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

57
Bu yalnızca etkinliğe sahipseniz işe yarar. Kontrol üzerinde yapmayı deneyin.
Delyan

226
... ve etkinliğe sahipseniz FindClicked = null;, daha basit olanları yazabilirsiniz .
Jon Skeet

79
FindClicked nedir?
Levitikon

3
Bu Kinect olayları için işe yaramaz - kinect.ColorFrameReady -= MyEventHanderyapar, ancak GetInvocationList()delegeleri üzerinde yineleme yapmak için kinect örnekleri üzerinde bir yöntem yoktur .
Brent Faust

GetInvocationListbulunamadı.
Joke Huang

75

Gönderen Tüm olay işleyicileri Çıkarma :

Doğrudan hayır, büyük ölçüde, etkinliği basitçe null olarak ayarlayamazsınız.

Dolaylı olarak, gerçek etkinliği özel hale getirebilir ve bunun etrafında, toplanan / çıkarılan tüm delegeleri izleyen bir özellik oluşturabilirsiniz.

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

4
Ben OP bu tür bir sarma mümkün olmayabilir genel .net kontrolleri atıfta olduğunu düşündüm.
Gishu

4
kontrolü elde edebilirsiniz, o zaman olur
Tom Fobear

Bu aynı zamanda potansiyel müşteri, iki listeyi korumak görmek stackoverflow.com/questions/91778/... reset için veya stackoverflow.com/questions/91778/... listesine erişebilirsiniz.
TN.

63

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

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

4
BU Sürüm benim için çalışıyordu. Kabul edilen sürüm çalışmadı. Bunun için +1.
Meister Schnitzel

1
BindingFlags.Publicİlk GetFieldaramada kullanılana kadar WPF etkinlikleri için çalışmadı .
Lennart

40

Var olmayan bir olay işleyicisini silmek herhangi bir zarar vermez. Hangi işleyicilerin olabileceğini biliyorsanız, hepsini silebilirsiniz. Ben de benzer bir davam vardı. 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;

16

Aslında bu yöntemi kullanıyorum ve mükemmel çalışıyor. Burada Aeonhack 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 vardır.

Hata ayıklama, d.targetnesnenin olayı nasıl işlediğini görebilirsiniz ved.method yöntemini görebilirsiniz. Sadece kaldırmanız gerekiyor.

Harika çalışıyor. Olay işleyicileri nedeniyle artık GC'lenemeyen nesne yok.


2
Lütfen başka dillerde cevap yazmayın.
Hille

10

Burada gösterilen tam çözümlerden nefret ettim, bir karışım yaptım ve şimdi 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 kaldırmak için genel bir yerel yöntem kullandığım ve farklı temsilciler ayarlandığında farklı durumlarda sonra yerel yöntem çağrıldığından kullandım.


4

Bunu gerçekten yapmak zorunda kalırsanız ... düşünmek ve bunu yapmak biraz zaman alacaktır. Olay işleyicileri, bir denetim içindeki olay-temsilci-haritasında yönetilir. Yapmanız gerekecek

  • Bu haritayı kontrol örneğinde yansıtın ve edinin.
  • Her etkinlik için tekrarlayın, temsilci alın
    • her delege, zincirleme bir dizi olay işleyicisi olabilir. Bu yüzden obControl.RemoveHandler öğesini (olay, işleyici) arayın

Kısacası, çok iş var. Teoride mümkün ... Hiç böyle bir şey denemedim.

Kontrol için abonelikten çıkma aşaması üzerinde daha iyi kontrol / disipline sahip olup olmadığınıza bakın.


3

Stephen'ın hakkı var. 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;
        }
    }
}

38
Tanrım, derleyici bu tür değişken isimleri yasaklamalıdır. graphs_must_be_redrawn Fransızca.
Gracchus'un

4
Fransızcadan çeviri foreach (EventHandler<MyCompletedArgs> handler in CompletionCompleted.GetInvocationList()) { CompletionCompleted -= handler; }
Anton K

@AntonK tarafından İngilizce çeviri iyi çalışıyor. Özellik işleyicisinde null olup olmadığını kontrol etmeyi unutmayın.
Brett

2

WinForms denetiminin bir özelliğini ayarlarken olayları nasıl askıya alacağımı buldum . Tüm olayları bir denetimden kaldıracaktır:

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

    }
}

1
Bu çok yardımcı oldu, ancak değiştirilmesi gereken bir şey var: Özgeçmiş () 'de işleyicileri ters sırayla ekliyorsunuz (Geriye doğru çalışmak istediğiniz Suppress'ten bir kopya / yapıştır olduğunu varsayıyorum. yinelediğiniz bir koleksiyonla uğraşmamak için). Bazı kodlar belirli bir sırayla ateşlenen işleyicilere güvenir, bu nedenle bunlarla uğraşmamak gerekir.
Michael

1

Vay. Bu çözümü buldum, ama istediğim gibi hiçbir şey işe yaramadı. 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);
}

Bu kesinlikle önceki yanıttan daha temiz. Aynı şeyi yapıyor mu? Öyle görünüyor, ama belki de bir şey eksik. Ayrıca, tüm istediğiniz EventHandlerList olduğunda neden yeni bir nesne oluşturmanız gerekiyor? EventHandlerList için erişilebilen bir c-tor yok mu, öyle ki sadece bir Bileşen için dahili olarak inşa edilmiş bir tane alabilir mi?
Michael

1

Bu sayfa bana çok yardımcı oldu. Buradan aldığım kod, bir düğmeden bir tıklama etkinliğini kaldırmak anlamına geliyordu. Bazı panellerden çift tıklama olaylarını ve bazı düğmelerden tıklama olaylarını kaldırmam gerekiyor. Bu nedenle, belirli bir olay için tüm olay işleyicilerini kaldıracak bir kontrol uzantısı oluşturdum.

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 uzamanın kullanımı. Bir düğmeden tıklama etkinliklerini kaldırmanız gerekiyorsa,

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

Bir panelden doubleclick etkinliklerini kaldırmanız gerekiyorsa,

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

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


1
.CastTo <> () uzantısı yöntemi tam olarak nerede bulunur?
IbrarMumtaz

Sadece kendiniz yazabilirsiniz: public static T CastTo <T> (bu nesne objectToCast) {return (T) objectToCast; }
KingOfHococrites

0

Bazen ThirdParty kontrolleri ile çalışmak zorunda kalırız ve bu garip çözümleri geliştirmemiz gerekir. @Anoop Muraleedharan cevabına dayanarak bu çözümü çıkarsama türü 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

Douglas tarafından başka bir çalışma çözümü buldum .

Bu yöntem, bir öğedeki belirli bir routet olayında ayarlanan tüm olay işleyicilerini kaldırır.
Gibi kullanın

Remove_RoutedEventHandlers(myImage, Image.MouseLeftButtonDownEvent);

Tam kod:

/// <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

düğmesi için tüm işleyicileri kaldırır: 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();
    }
}

-1

Burada, ilişkili bir etkinliği kaldırmak için başka bir çözüm daha var (zaten denetim için olayları işlemek için bir yönteminiz varsa):

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

Bunu sadece yapabilirsiniz. Buton. Bu nedenle, hangi satırın kaldırılacağını, özellikle satır içi olmaları durumunda nasıl bulunacağı sorusunun çözümüne yardımcı olmaz.
Softlion

-1

Bu OP'ye bir cevap değil, ama başkalarına yardımcı olması durumunda 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);
  }

-3

Bu cevabı buldum ve neredeyse ihtiyaçlarıma uyuyordu. Sınıf için SwDevMan81'e teşekkürler. Tek tek yöntemlerin bastırılmasına ve sürdürülmesine izin vermek için değiştirdim ve burada yayınlayacağımı düşündüm.

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

8
Bu kıvrık bir çözümdür ve endüstriyel sınıf yazılımlarda asla kullanılmamalıdır. En iyi yaklaşım belirtildiği gibidir: Etkinlik aboneliğinizi ve abonelikten çıkma durumunuzu iyi yönetin ve bu tür sorunlarla hiç karşılaşmayacaksınız.
Tri Q Tran

Unwire olayları yansıtmamamız gerektiğini kabul ediyorum ve olay aboneliği ve aboneliği iptal etme uygulama tarafından yönetilmelidir. Tartışılan konunun DEBUG zamanında kullanılması gerektiğini düşünüyorum. Yeniden düzenleme yaptığınız eski uygulamalarda bu bir zorunluluktur.
Tiago Freitas Leal
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.