如何去除“button”的“点击”事件的所有事件处理程序?

我有一个button控件,我需要删除所有附加到其Click事件的事件处理程序。

这怎么可能?

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

你基本上不能,至less不能没有反思和很多的不满。

事件是严格的“订阅,取消订阅” – 你不能取消订阅别人的处理程序,除了你可以改变别人对对象的引用。

注意 :由于我发布了原始答案的问题已经作为这个问题的重复被closures,所以我在这里交叉发布了一个我的答案的改进版本。 这个答案只适用于WPF。 它不适用于Windows窗体或任何其他UI框架。

下面是一个有用的实用方法,用于删除订阅给定元素上的路由事件的所有事件处理程序。 如果你喜欢,你可以简单地把它转换成扩展方法。

 /// <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="routedEvent">The routed event for which to remove the event handlers.</param> 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); } 

然后,您可以轻松地为您的button的Click事件调用此实用程序方法:

 RemoveRoutedEventHandlers(button, Button.ClickEvent); 

编辑 :我已经复制了由corona实现的错误修复 ,当没有事件处理程序订阅时,它停止抛出NullReferenceException的方法。 信用(和upvotes)应该去他们的答案。

只是想扩大道格拉斯的例程,我非常喜欢。 我发现我需要添加额外的空检查eventHandlersStore来处理传递的元素没有任何附加事件的任何情况。

 /// <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="routedEvent">The routed event for which to remove the event handlers.</param> 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上find了这个答案:

如何从控件中删除所有事件处理程序

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

我想这可以做得更好,但它适用于我目前的需要。 希望这对某个人有用。