¿Cómo sería posible eliminar todos los controladores de eventos del evento ‘Hacer clic’ de un ‘Botón’?

Tengo un botón de control, y tendría que eliminar todos los controladores de eventos adjuntos a su evento Click .

¿Cómo sería eso posible?

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

No se puede, básicamente, al menos no sin reflexión y mucha suciedad.

Los eventos son estrictamente “suscribirse, darse de baja”: no puede cancelar la suscripción del controlador de otra persona, del mismo modo que no puede cambiar la referencia de otra persona a un objeto.

Nota : dado que la pregunta sobre la que publiqué mi respuesta original se cerró como un duplicado de esta pregunta, estoy publicando una versión mejorada de mi respuesta aquí. Esta respuesta solo se aplica a WPF. No funcionará en Windows Forms ni en ningún otro marco de interfaz de usuario.

El siguiente es un útil método de utilidad para eliminar todos los controladores de eventos suscritos a un evento enrutado en un elemento dado. Puede convertirlo trivialmente en un método de extensión si lo desea.

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

A continuación, podría llamar fácilmente a este método de utilidad para el evento Click su botón:

 RemoveRoutedEventHandlers(button, Button.ClickEvent); 

Editar : Copié la corrección de errores implementada por corona , que impide que el método NullReferenceException una NullReferenceException cuando no hay suscriptores de eventos. El crédito (y los votos a favor) deberían ir a su respuesta.

Solo quería expandir ligeramente la rutina de Douglas, lo cual me gustó mucho. Descubrí que necesitaba agregar el cheque nulo adicional a eventHandlersStore para manejar cualquier caso en el que el elemento pasado aún no tuviera ningún evento conectado.

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

Encontré esta respuesta aquí en StackOverflow:

Cómo eliminar todos los controladores de eventos de un control

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

Que el cartel original encontró aquí :

Tuve el problema de error nulo con el código que Jamie Dixon publicó para incorporar a la cuenta que no tiene un evento 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]); } } 

Luego, un pequeño cambio y debería ser para cualquier evento.

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

Me imagino que esto podría mejorar, pero funciona para mi necesidad actual. Espero que esto sea útil para alguien.