कैसे एक घटना से सभी घटना संचालकों को दूर करने के लिए


366

एक नियंत्रण पर एक नया ईवेंट हैंडलर बनाने के लिए आप ऐसा कर सकते हैं

c.Click += new EventHandler(mainFormButton_Click);

या यह

c.Click += mainFormButton_Click;

और किसी इवेंट हैंडलर को निकालने के लिए आप ऐसा कर सकते हैं

c.Click -= mainFormButton_Click;

लेकिन आप सभी ईवेंट हैंडलर को किसी ईवेंट से कैसे हटाते हैं?


10
यदि कोई भी WPF समाधान की तलाश में यहां आया है, तो आप इस उत्तर को देखना चाह सकते हैं ।
डगलस

1
क्या आप सेट नहीं कर सकते c.Click = null?
18

यह उन चीजों में से एक है, जो मुझे हास्यास्पद रूप से अधिक जटिल लगते हैं। एक सरल Clearतरीका बहुत अधिक स्पष्ट रूप से प्रयास किया गया था
Zimano

जवाबों:


167

मुझे MSDN मंचों पर एक समाधान मिला । नीचे दिया गया नमूना कोड सभी Clickघटनाओं को हटा देगा 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]);
        }
    }
}

यदि बटन 1 को शून्य पर सेट किया गया है, तो क्या सभी इवेंट हैंडलर बटन 1 से जुड़े हुए हैं।
डेमियन

3
अगर मैं गलत हूं तो मुझे सुधारें, लेकिन RemoveClickEventशुरुआत की पहली पंक्ति के साथ नहीं होना चाहिए FieldInfo f1 = typeof(Button):? GetFieldयदि मैं उपयोग करता हूं तो मुझे अशक्त हो जाता है Control
रक्षक एक

2
यह ToolStripButtons के लिए काम नहीं करता है। मैंने ToolStripButton के साथ RemoveClickEvent में बटन को बदल दिया है, लेकिन RemoveClickEvent को कॉल करने के बाद भी घटनाएँ जारी हैं। क्या किसी के पास इस समस्या का हल है?
स्कल्ली

1
MSDN में उपरोक्त लिंक भी myButton.Click + = null को आज़माने का सुझाव देता है; अगर आप सभी प्रतिनिधियों को हटाना चाहते हैं (क्लिक के लिए नहीं, बल्कि अन्य घटनाओं के लिए ..)
hello_earth

1
@hello_earth के लिए काम करने के लिए प्रतीत नहीं होता हैObservableCollection.CollectionChanged += null;
माइक डी

146

आप लोग इस WAY को अपने आप पर बहुत कठिन बना रहे हैं। यह आसान है:

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

57
यह तभी काम करेगा जब आप घटना के मालिक होंगे। इसे एक नियंत्रण पर करने का प्रयास करें।
डेलीन

226
... और यदि आप इस घटना के मालिक हैं, तो आप सिर्फ वही लिख सकते हैं FindClicked = null;जो सरल हो।
जॉन स्कीट

79
FindClicked क्या है?
लेविटिकन

3
यह काइनेट घटनाओं के लिए काम नहीं करता है - kinect.ColorFrameReady -= MyEventHanderकरता है, लेकिन GetInvocationList()उनके प्रतिनिधियों पर पुनरावृति करने के लिए किनेक्ट उदाहरणों पर कोई विधि नहीं है ।
ब्रेंट फस्ट

GetInvocationListनहीं मिला।
मजाक हुआ

75

सभी ईवेंट हैंडलर्स को हटाने से :

सीधे तौर पर नहीं, बड़े हिस्से में क्योंकि आप घटना को शून्य करने के लिए निर्धारित नहीं कर सकते।

परोक्ष रूप से, आप वास्तविक घटना को निजी बना सकते हैं और इसके चारों ओर एक संपत्ति बना सकते हैं जो सभी प्रतिनिधियों को इसमें जोड़े / घटाए जाने पर नज़र रखता है।

निम्नलिखित लें:

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
मुझे लगा कि ओपी सामान्य .net नियंत्रणों का जिक्र कर रहा है .. जिसमें इस तरह की रैपिंग संभव नहीं है।
शिशु

4
आप नियंत्रण को प्राप्त कर सकते हैं, तब यह होगा
टॉम फोबियर

यह दो सूचियों को बनाए रखने के लिए भी जाता है, सूची को एक्सेस करने के लिए stackoverflow.com/questions/91778/… को रीसेट या stackoverflow.com/questions/91778/… के लिए देखें।
टीएन।

63

स्वीकृत उत्तर पूर्ण नहीं है। यह {ऐड के रूप में घोषित घटनाओं के लिए काम नहीं करता है; हटाना;}

यहाँ काम कर रहा है कोड:

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
यह संस्करण मेरे लिए काम कर रहा था। स्वीकृत संस्करण काम नहीं किया। उसके लिए +1।
मिस्टर श्नीटज़ेल

1
जब तक मैं BindingFlags.Publicपहली GetFieldकॉल में इस्तेमाल नहीं करता तब तक WPF इवेंट के लिए काम नहीं किया ।
लेन्नर्ट

40

यह गैर-मौजूदा ईवेंट हैंडलर को हटाने के लिए कोई नुकसान नहीं करता है। इसलिए यदि आप जानते हैं कि क्या हैंडलर हो सकते हैं, तो आप बस उन सभी को हटा सकते हैं। मेरे पास भी ऐसा ही मामला था। यह कुछ मामलों में मदद कर सकता है।

पसंद:

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

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

16

मैं वास्तव में इस पद्धति का उपयोग कर रहा हूं और यह पूरी तरह से काम करता है। मैं यहाँ Aeonhack द्वारा लिखे गए कोड से 'प्रेरित' था ।

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 छिपा हुआ है, लेकिन यह मौजूद है।

डिबगिंग, आप देख सकते हैं कि d.targetवस्तु वास्तव में घटना को कैसे संभालती है, और d.methodइसकी विधि क्या है। आपको केवल इसे निकालना है।

यह बहुत अच्छा काम करता है। घटना संचालकों की वजह से कोई और वस्तु GC'ed नहीं हो रही है।


2
कृपया अन्य भाषाओं में उत्तर न लिखें।
हेल्ले

10

मुझे यहां दिखाए गए किसी भी पूर्ण समाधान से नफरत है, मैंने एक मिश्रण किया और अब परीक्षण किया, किसी भी घटना हैंडलर के लिए काम किया:

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

आसान! स्टीफन पुनाक के लिए धन्यवाद।

मैंने इसका इस्तेमाल किया क्योंकि मैं प्रतिनिधियों को हटाने के लिए एक सामान्य स्थानीय विधि का उपयोग करता हूं और स्थानीय प्रतिनिधि को विभिन्न मामलों के बाद बुलाया जाता है, जब विभिन्न प्रतिनिधियों का निपटान किया जाता है।


4

यदि आप वास्तव में यह करना है ... यह प्रतिबिंब और यह करने के लिए कुछ समय लगेगा। इवेंट हैंडलर एक कंट्रोल के अंदर एक इवेंट-टू-डेलीगेट-मैप में प्रबंधित होते हैं। आपको करने की आवश्यकता होगी

  • नियंत्रण उदाहरण में इस मानचित्र को प्रतिबिंबित और प्राप्त करें।
  • प्रत्येक घटना के लिए Iterate, प्रतिनिधि प्राप्त करें
    • बदले में प्रत्येक प्रतिनिधि घटना संचालकों की एक श्रृंखलाबद्ध श्रृंखला हो सकता है। तो obControl को बुलाओ। RemoveHandler (घटना, हैंडलर)

संक्षेप में, बहुत सारा काम। यह सिद्धांत में संभव है ... मैंने कभी इस तरह की कोशिश नहीं की।

देखें कि क्या आपके पास नियंत्रण के लिए सदस्यता-सदस्यता समाप्त चरण पर बेहतर नियंत्रण / अनुशासन हो सकता है।


3

स्टीफन का अधिकार है। यह बहुत आसान है:

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
भगवान, संकलक को उस तरह के चर नामों का निषेध करना चाहिए। फ्रेंच में graphs_must_be_redrawn।
ग्राकस

4
फ्रेंच से अनुवाद foreach (EventHandler<MyCompletedArgs> handler in CompletionCompleted.GetInvocationList()) { CompletionCompleted -= handler; }
एंटोन के

@AntonK द्वारा अंग्रेजी अनुवाद अच्छी तरह से काम करता है। प्रॉपर्टी हैंडलर पर नल की जांच करना याद रखें।
ब्रेट

2

मैंने पाया कि WinForms नियंत्रण की संपत्ति सेट करते समय घटनाओं को कैसे निलंबित किया जाए । यह सभी घटनाओं को नियंत्रण से हटा देगा:

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
यह बहुत मददगार था, लेकिन एक चीज है जिसे बदलने की जरूरत है: रिज्यूमे () में, आप हैंडलर को रिवर्स ऑर्डर में वापस जोड़ रहे हैं (मैं मान रहा हूं कि यह सप्रेस से कॉपी / पेस्ट है, जहां आप पीछे की ओर काम करना चाहते हैं। के रूप में एक संग्रह के साथ गड़बड़ करने के लिए नहीं है कि आप इसे खत्म कर रहे हैं)। कुछ कोड दिए गए क्रम में हैंडलर फायरिंग पर गिना करते हैं, इसलिए किसी को उसके साथ गड़बड़ नहीं करनी चाहिए।
माइकल

1

वाह। मुझे यह समाधान मिला, लेकिन जैसा मैंने चाहा, वैसा कुछ भी नहीं हुआ। लेकिन यह बहुत अच्छा है:

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

यह निश्चित रूप से पिछले उत्तर की तुलना में शून्य है। क्या यह बिल्कुल वैसा ही काम करता है? ऐसा लगता है कि यह करता है, लेकिन शायद मुझे कुछ याद आ रहा है। इसके अलावा, आपको एक नई वस्तु बनाने की आवश्यकता क्यों है जब आप चाहते हैं कि एक EventHandlerList है? क्या EventHandlerList के लिए कोई सी-टॉर सुलभ नहीं है, जैसे कि केवल एक ही प्राप्त किया जा सकता है जो एक घटक के लिए आंतरिक रूप से बनाया गया है?
माइकल

1

इस पेज ने मुझे बहुत मदद की। यहां से मुझे मिला कोड एक बटन से क्लिक करने की घटना को हटाने के लिए था। मुझे कुछ पैनलों से डबल क्लिक की घटनाओं को हटाने और कुछ बटन से घटनाओं को क्लिक करने की आवश्यकता है। इसलिए मैंने एक नियंत्रण विस्तार किया, जो एक निश्चित घटना के लिए सभी घटना संचालकों को हटा देगा।

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

अब, इस विलोपन का उपयोग। यदि आपको एक बटन से क्लिक घटनाओं को हटाने की आवश्यकता है,

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

यदि आपको किसी पैनल से डबलक्लिक आयोजनों को हटाने की आवश्यकता है,

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

मैं C # का विशेषज्ञ नहीं हूं, इसलिए यदि कोई कीड़े हैं तो कृपया मुझे क्षमा करें और कृपया मुझे इसके बारे में बताएं।


1
.CastTo <> () विस्तार विधि जहां वास्तव में पाया जाता है?
IbrarMumtaz 16

आप बस अपना स्वयं का लिख ​​सकते हैं: सार्वजनिक स्थैतिक टी कास्टो <टी> (यह ऑब्जेक्ट ऑब्जेक्टटैस्ट) {रिटर्न (टी) ऑब्जेक्टटॉक्स; }
KingOfHypocrites

0

कभी-कभी हमें थर्डपार्टी नियंत्रण के साथ काम करना पड़ता है और हमें इन अजीब समाधानों का निर्माण करने की आवश्यकता होती है। @Anoop मुरलीधरन के जवाब के आधार पर मैंने यह समाधान inference प्रकार और ToolStripItem समर्थन के साथ बनाया है

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

और आप इसे इस तरह से उपयोग कर सकते हैं

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

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

0

मुझे डगलस द्वारा एक और काम करने वाला समाधान मिला ।

यह विधि उन सभी ईवेंट हैंडलर को हटा देती है, जो किसी तत्व पर किसी विशिष्ट रूटिंग ईवेंट पर सेट किए जाते हैं।
इसका उपयोग करें

Remove_RoutedEventHandlers(myImage, Image.MouseLeftButtonDownEvent);

पूर्ण कोड:

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

बटन के लिए सभी हैंडलर निकालता है: save.emoveEvents ();

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

ठीक है, यहाँ एक अलग घटना को हटाने के लिए एक और उपाय है (यदि आपके पास नियंत्रण के लिए घटनाओं को संभालने के लिए पहले से ही एक विधि है):

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

आप बस इसे कर सकते हैं। बटन 1। पति / पत्नी - = प्रतिनिधि। क्रेडिटलेगेट (टाइपऑफ (इवेंटहैंडलर), यह, "बटन 1_माउसडाउन क्लीक्ड")। इसलिए यह उस सवाल को हल करने में मदद नहीं करेगा जो यह पता लगाना है कि किस प्रतिनिधि को निकालना है, खासकर यदि वे इनलाइन थे।
सॉफ्टलिऑन

-1

यह ओपी का जवाब नहीं है, लेकिन मुझे लगा कि मैं इसे यहां पोस्ट करूंगा क्योंकि यह दूसरों की मदद कर सकता है।

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

मुझे यह उत्तर मिला और यह मेरी आवश्यकताओं के अनुरूप है। वर्ग के लिए SwDevMan81 का धन्यवाद। मैंने इसे अलग-अलग तरीकों से दमन और फिर से शुरू करने की अनुमति देने के लिए संशोधित किया है, और मुझे लगा कि मैं इसे यहां पोस्ट करूंगा।

// 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
यह एक जटिल समाधान है और इसका उपयोग कभी भी औद्योगिक ग्रेड सॉफ्टवेयर में नहीं किया जाना चाहिए। सबसे अच्छा तरीका है जैसा कि उल्लेख किया गया है: अपनी घटना की सदस्यता और संयुक्त राष्ट्र की सदस्यता अच्छी तरह से प्रबंधित करें और आप कभी भी ऐसी समस्याओं का सामना नहीं करेंगे।
त्रि क्यू ट्रान

मैं मानता हूं कि हमें घटनाओं को उजागर करने के लिए प्रतिबिंब का उपयोग नहीं करना चाहिए, और घटना सदस्यता और संयुक्त राष्ट्र की सदस्यता को एप्लिकेशन द्वारा प्रबंधित किया जाना चाहिए। मुझे लगता है कि डिबेट के समय डिबग में इस मुद्दे का इस्तेमाल किया जाना चाहिए, यह पता लगाने के लिए कि हम कुछ कर रहे हैं। यह एक ऐसी विरासत अनुप्रयोगों पर होना चाहिए जो आप फिर से तैयार कर रहे हैं।
टियागो फ्रीटास ने
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.