Как можно удалить все обработчики событий события «Click» кнопки «Button»?

У меня есть кнопка управления, и мне нужно будет удалить все обработчики событий, прикрепленные к событию Click .

Как это возможно?

Button button = GetButton(); button.Click.RemoveAllEventHandlers(); 

Вы не можете, в принципе – по крайней мере, не без размышлений и много грубости.

События строго «подписываются, отписываются» – вы не можете отменить подписку чужого обработчика, больше, чем вы можете изменить чужую ссылку на объект.

Примечание . Поскольку вопрос, по которому я опубликовал свой первоначальный ответ, был закрыт как дубликат этого вопроса, я перекрестно размещаю улучшенную версию моего ответа здесь. Этот ответ применим только к WPF. Он не будет работать в Windows Forms или в любом другом интерфейсе пользовательского интерфейса.

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

 ///  /// Removes all event handlers subscribed to the specified routed event from the specified element. ///  /// The UI element on which the routed event is defined. /// The routed event for which to remove the event handlers. public static void RemoveRoutedEventHandlers(UIElement element, RoutedEvent routedEvent) { // Get the EventHandlersStore instance which holds event handlers for the specified element. // The EventHandlersStore class is declared as internal. var eventHandlersStoreProperty = typeof(UIElement).GetProperty( "EventHandlersStore", BindingFlags.Instance | BindingFlags.NonPublic); object eventHandlersStore = eventHandlersStoreProperty.GetValue(element, null); // If no event handlers are subscribed, eventHandlersStore will be null. // Credit: https://stackoverflow.com/a/16392387/1149773 if (eventHandlersStore == null) return; // Invoke the GetRoutedEventHandlers method on the EventHandlersStore instance // for getting an array of the subscribed event handlers. var getRoutedEventHandlers = eventHandlersStore.GetType().GetMethod( "GetRoutedEventHandlers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); var routedEventHandlers = (RoutedEventHandlerInfo[])getRoutedEventHandlers.Invoke( eventHandlersStore, new object[] { routedEvent }); // Iteratively remove all routed event handlers from the element. foreach (var routedEventHandler in routedEventHandlers) element.RemoveHandler(routedEvent, routedEventHandler.Handler); } 

Затем вы можете легко вызвать этот метод утилиты для события Click вашей кнопки:

 RemoveRoutedEventHandlers(button, Button.ClickEvent); 

Изменить : я скопировал исправление ошибок, реализованное короной , что не позволяет методу выбросить NullReferenceException когда подписчики событий не подписаны. Кредит (и upvotes) должен пойти на их ответ.

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

 ///  /// Removes all event handlers subscribed to the specified routed event from the specified element. ///  /// The UI element on which the routed event is defined. /// The routed event for which to remove the event handlers. public static void RemoveRoutedEventHandlers(UIElement element, RoutedEvent routedEvent) { // Get the EventHandlersStore instance which holds event handlers for the specified element. // The EventHandlersStore class is declared as internal. var eventHandlersStoreProperty = typeof(UIElement).GetProperty( "EventHandlersStore", BindingFlags.Instance | BindingFlags.NonPublic); object eventHandlersStore = eventHandlersStoreProperty.GetValue(element, null); if (eventHandlersStore == null) return; // Invoke the GetRoutedEventHandlers method on the EventHandlersStore instance // for getting an array of the subscribed event handlers. var getRoutedEventHandlers = eventHandlersStore.GetType().GetMethod( "GetRoutedEventHandlers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); var routedEventHandlers = (RoutedEventHandlerInfo[])getRoutedEventHandlers.Invoke( eventHandlersStore, new object[] { routedEvent }); // Iteratively remove all routed event handlers from the element. foreach (var routedEventHandler in routedEventHandlers) element.RemoveHandler(routedEvent, routedEventHandler.Handler); } 

Я нашел этот ответ здесь, в StackOverflow:

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

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

Какой оригинальный плакат найден здесь :

У меня была ошибка с ошибкой с кодом Jamie Dixon, опубликованным для входа в аккаунт, не имеющий события Click.

 private void RemoveClickEvent(Control control) { // chenged "FieldInfo f1 = typeof(Control)" to "var f1 = b.GetType()". By changing to // the type of the passed in control we can use this for any control with a click event. // using var allows for null checking and lowering the chance of exceptions. var fi = control.GetType().GetField("EventClick", BindingFlags.Static | BindingFlags.NonPublic); if (fi != null) { object obj = fi.GetValue(control); PropertyInfo pi = control.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance); EventHandlerList list = (EventHandlerList)pi.GetValue(control, null); list.RemoveHandler(obj, list[obj]); } } 

Затем небольшое изменение, и это должно быть для любого события.

 private void RemoveClickEvent(Control control, string theEvent) { // chenged "FieldInfo f1 = typeof(Control)" to "var f1 = b.GetType()". By changing to // the type of the passed in control we can use this for any control with a click event. // using var allows for null checking and lowering the chance of exceptions. var fi = control.GetType().GetField(theEvent, BindingFlags.Static | BindingFlags.NonPublic); if (fi != null) { object obj = fi.GetValue(control); PropertyInfo pi = control.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance); EventHandlerList list = (EventHandlerList)pi.GetValue(control, null); list.RemoveHandler(obj, list[obj]); } } 

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

  • Событие Internet Explorer и JavaScript currentTarget
  • Как изменить Form1 label.text при установке флажка на form2?
  • Получить отредактированный TreeNode от CellEditorListener
  • Обнаружение событий вставки / удаления USB в Windows с использованием C ++
  • Остановить распространение событий мыши в угловом
  • События WPF в ResourceDictionary для ControlTemplate
  • Подписка на динамические события C #
  • Что означает «Захват мыши» в WPF?
  • Как я могу сделать свое собственное событие на C #?
  • Как захватить щелчок мышью по элементу в ListBox в WPF?
  • Должен ли я избегать обработчиков событий async void?
  • Давайте будем гением компьютера.