Как удалить все обработчики событий из события

Чтобы создать новый обработчик событий в элементе управления, вы можете сделать это

c.Click += new EventHandler(mainFormButton_Click);

или это

c.Click += mainFormButton_Click;

и удалить обработчик события, вы можете сделать это

c.Click -= mainFormButton_Click;

Но как удалить все обработчики событий из события?

18.09.2008 11:34:23
Если кто-то пришел сюда в поисках решения WPF, вы можете посмотреть на этот ответ .
Douglas 27.09.2012 09:49:22
Вы не можете просто установить c.Click = null?
alexania 6.02.2020 18:04:38
Это одна из тех вещей, которые я нахожу до смешного слишком сложными. Простой Clearметод был слишком много усилий, по-видимому
Zimano 21.04.2020 09:21:21
18 ОТВЕТОВ
РЕШЕНИЕ

Я нашел решение на форумах 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]);
        }
    }
}
166
10.05.2011 20:33:35
Если button1 установлен в null, все обработчики событий присоединены к button1.Click правильно расположены?
Damien 29.07.2009 04:12:55
Поправьте меня , если я ошибаюсь, но не стоит на первой линии RemoveClickEventстарта с: FieldInfo f1 = typeof(Button)? Я получаю ноль, GetFieldесли я использую Control.
Protector one 11.11.2011 10:42:47
Это, похоже, не работает для ToolStripButtons. Я заменил Button в RemoveClickEvent на ToolStripButton, но события все еще остаются в месте после вызова RemoveClickEvent. У кого-нибудь есть решение этой проблемы?
Skalli 21.11.2011 09:22:13
ссылка выше в MSDN также предлагает попробовать myButton.Click + = null; если вы хотите удалить всех делегатов (не для Click, а для других событий ..)
hello_earth 31.05.2013 12:37:48
@hello_earth Кажется, не работаетObservableCollection.CollectionChanged += null;
Mike de Klerk 15.10.2013 08:12:47

От удаления всех обработчиков событий :

Напрямую нет, во многом потому, что вы не можете просто установить событие в null.

Косвенным образом вы можете сделать фактическое событие приватным и создать вокруг него свойство, которое будет отслеживать всех делегатов, добавляемых / вычитаемых к нему.

Возьмите следующее:

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();
}
75
1.11.2014 20:22:53
Я думал, что OP ссылается на общие элементы управления .net .., в которых этот вид упаковки может быть невозможен.
Gishu 18.09.2008 11:47:05
Вы могли бы получить контроль, тогда это будет
Tom Fobear 13.04.2011 16:06:38
Это также ведет к поддержанию двух списков, см. Stackoverflow.com/questions/91778/… для сброса или stackoverflow.com/questions/91778/… для доступа к списку.
TN. 4.09.2013 13:45:12

Если вам действительно придется сделать это ... это займет отражение и достаточно времени, чтобы сделать это. Обработчики событий управляются в карте события для делегирования внутри элемента управления. Вам нужно будет

  • Отразите и получите эту карту в контрольном экземпляре.
  • Итерировать для каждого события, получить делегата
    • каждый делегат в свою очередь может быть цепочкой обработчиков событий. Так что вызовите obControl.RemoveHandler (событие, обработчик)

Короче, много работы. Это возможно в теории ... Я никогда не пробовал что-то подобное.

Посмотрите, сможете ли вы лучше контролировать / дисциплинировать фазу подписки-отписки для контроля.

4
11.09.2013 08:09:17

Это не вредит удалению несуществующего обработчика событий. Так что, если вы знаете, какие там могут быть обработчики, вы можете просто удалить их все. У меня просто был похожий случай. Это может помочь в некоторых случаях.

Подобно:

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

// Remove handlers...
c.Click -= DoesSomething;
c.Click -= DoesSomethingElse;
40
5.10.2013 11:44:30

Я только что нашел, как приостановить события при установке свойства элемента управления 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]);
            }
        }

    }
}
2
1.11.2014 20:21:06
Это было очень полезно, но есть одна вещь, которую нужно изменить: в Resume () вы добавляете обработчики обратно в обратном порядке (я предполагаю, что это копирование / вставка из Suppress, где вы хотите работать в обратном направлении, так что как не связываться с коллекцией, которую вы повторяете). Некоторый код рассчитан на обработчики, запускаемые в заданном порядке, поэтому не стоит с этим связываться.
Michael 29.12.2014 16:14:46

Я нашел этот ответ, и он почти соответствует моим потребностям. Спасибо 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);
                    }
                }
            }
        }
    } 
}
-3
11.08.2010 16:17:33
Это запутанное решение и никогда не должно использоваться в программном обеспечении промышленного уровня. Лучший подход, как уже упоминалось: хорошо управляйте подпиской на события и отменой подписки, и вы никогда не столкнетесь с такими проблемами.
Tri Q Tran 25.06.2010 02:42:38
Я согласен, что мы не должны использовать рефлексию для разветвления событий, и приложение должно управлять подпиской на события и отменой подписки. Я думаю, что обсуждаемый вопрос следует использовать во время отладки, чтобы выяснить, что мы что-то делаем. Это необходимо для устаревших приложений, которые вы реорганизуете.
Tiago Freitas Leal 27.12.2014 18:21:37

Я на самом деле использую этот метод, и он отлично работает. Я был «вдохновлен» кодом, написанным здесь 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'ами из-за обработчиков событий.

16
8.04.2016 21:53:13
Пожалуйста, не пишите ответы на других языках.
Hille 28.10.2019 11:14:26

Вы, ребята, делаете этот путь слишком тяжело для себя. Это так просто:

void OnFormClosing(object sender, FormClosingEventArgs e)
{
    foreach(Delegate d in FindClicked.GetInvocationList())
    {
        FindClicked -= (FindClickedHandler)d;
    }
}
145
29.03.2011 15:59:19
Это будет работать только если у вас есть событие. Попробуйте сделать это на контроле.
Delyan 19.05.2011 20:20:36
... и если у вас есть событие, вы можете просто написать, FindClicked = null;что проще.
Jon Skeet 8.10.2012 16:42:28
Что такое FindClicked?
Levitikon 9.10.2012 16:31:19
Это не работает для событий Kinect - kinect.ColorFrameReady -= MyEventHanderработает, но в GetInvocationList()экземплярах kinect нет метода для перебора их делегатов.
Brent Faust 12.07.2013 01:44:31
GetInvocationListне найден.
Joke Huang 28.02.2020 18:49:22

Эта страница мне очень помогла. Код, который я получил отсюда, предназначался для удаления события нажатия кнопки. Мне нужно удалить события двойного щелчка с некоторых панелей и события щелчка с некоторых кнопок. Поэтому я сделал расширение элемента управления, которое удалит все обработчики событий для определенного события.

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
28.08.2018 08:53:56
Метод расширения .CastTo <> () где именно это найдено?
IbrarMumtaz 28.09.2011 16:58:08
Вы можете написать свой собственный: public static T CastTo <T> (этот объект objectToCast) {return (T) objectToCast; }
KingOfHypocrites 2.04.2012 15:46:45

Стивен имеет право. Это очень просто:

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;
        }
    }
}
3
9.09.2013 14:48:03
Боже, компилятор должен запретить такие имена переменных. graphs_must_be_redrawn по-французски.
gracchus 7.01.2013 22:07:31
Перевод с французского foreach (EventHandler<MyCompletedArgs> handler in CompletionCompleted.GetInvocationList()) { CompletionCompleted -= handler; }
Anton K 8.05.2015 22:29:43
Английский перевод @AntonK работает хорошо. Не забудьте проверить нулевое значение в обработчике свойств.
Brett 27.12.2016 13:50:12

Что ж, здесь есть другое решение для удаления связанного события (если у вас уже есть метод для обработки событий для элемента управления):

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
26.10.2011 07:05:46
Вы можете просто сделать это .button1.MouseDown - = Delegate.CreateDelegate (typeof (EventHandler), this, "button1_MouseDownClicked"). Так что это не поможет решить вопрос о том, как выяснить, какого делегата удалить, особенно если он был встроенным.
Softlion 24.10.2013 10:26:37

Принятый ответ не полный. Это не работает для событий, объявленных как {add; Удалить;}

Вот рабочий код:

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;
}
62
4.04.2016 13:59:32
Эта версия работала на меня. Принятая версия не работает. +1 за это.
Meister Schnitzel 11.03.2014 13:42:00
Не работал для событий WPF, пока я не использовал BindingFlags.Publicпервый GetFieldвызов.
Lennart 24.07.2017 09:52:31

Вау. Я нашел это решение, но ничего не получилось, как я хотел. Но это так хорошо

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);
}
1
28.02.2015 15:50:13
Это, конечно, аккуратнее, чем предыдущий ответ. Это делает то же самое? Похоже, что это так, но, возможно, я что-то упустил. Кроме того, зачем вам нужно создавать новый объект, когда все, что вам нужно, это EventHandlerList? Не существует ли c-tor, доступного для EventHandlerList, так что можно получить только тот, который был создан для компонента?
Michael 29.12.2014 16:19:58

Это не ответ на ФП, но я решил опубликовать это здесь на случай, если это поможет другим.

  /// <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);
  }
-1
29.06.2015 11:43:35

Я ненавидел все полные решения, показанные здесь, я сделал смесь и протестировал сейчас, работал для любого обработчика событий:

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

Легко! Спасибо за Стивена Пунака.

Я использовал его, потому что я использую общий локальный метод для удаления делегатов, а локальный метод вызывался после разных случаев, когда установлены разные делегаты.

9
21.07.2016 14:19:56

Иногда нам приходится работать с элементами управления ThirdParty, и нам нужно создавать эти неудобные решения. Основываясь на ответе @Anoop Muraleedharan, я создал это решение с типом логического вывода и поддержкой 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
16.09.2016 17:50:35

Я нашел другое рабочее решение Дугласа .

Этот метод удаляет все обработчики событий, которые установлены для конкретного события routet в элементе.
Используйте это как

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
28.10.2019 12:49:14

удаляет все обработчики для кнопки: 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();
    }
}
0
18.02.2020 17:42:03