如何删除所有的点击事件处理程序?

7

可能重复: 如何删除按钮的所有点击事件处理程序?

我想从一个按钮中删除所有的点击事件处理程序。我在Stack Overflow问题如何从控件中删除所有事件处理程序中找到了这个方法。

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

但是这行代码始终返回 null:
  typeof(Control).GetField("EventClick", BindingFlags.Static | BindingFlags.NonPublic);

这个方法是在2006年编写的。

是否有最新版本的此方法?

注意:我正在使用WPF.NET 4.0。


我对为什么会返回null并不能提供太多帮助,但是@JonSkeet在https://dev59.com/K2w15IYBdhLWcg3wGn9c 上有一个非常好的答案,解释了为什么这不可能没有使用反射。也许你需要以不同的方式来解决问题。 - Eric Andres
1
你试图解决的根本问题是什么/你试图实现的目标是什么? - RQDQ
你意识到你正在尝试将WinForms代码应用于WPF吗? - Douglas
如何动态地移除事件处理程序(使用反射)?是否有更好的方法?原文链接:https://dev59.com/02TWa4cB1Zd3GeqPIfdT - Dinis Cruz
1个回答

20
下面是一个有用的实用方法,可用于检索任何路由事件的所有已订阅事件处理程序:
/// <summary>
/// Gets the list of routed event handlers subscribed to the specified routed event.
/// </summary>
/// <param name="element">The UI element on which the event is defined.</param>
/// <param name="routedEvent">The routed event for which to retrieve the event handlers.</param>
/// <returns>The list of subscribed routed event handlers.</returns>
public static RoutedEventHandlerInfo[] GetRoutedEventHandlers(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);

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

    return routedEventHandlers;
}

利用上述方法,你的函数实现将变得非常简单:

private void RemoveClickEvent(Button b)
{
    var routedEventHandlers = GetRoutedEventHandlers(b, ButtonBase.ClickEvent);
    foreach (var routedEventHandler in routedEventHandlers)
        b.Click -= (RoutedEventHandler)routedEventHandler.Handler;
}

这是一个非常有用的答案,不幸的是它被附加在一个已关闭的问题上。我认为,如果您在那里也提供同样的答案,那么“重复”的内容将得到改进。 - phloopy
1
@phloopy:好建议。我刚刚在那里发布了上述解决方案的改进版本 - Douglas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接