C# 如何删除';单击';发生';按钮';?

C# 如何删除';单击';发生';按钮';?,c#,.net,events,event-handling,C#,.net,Events,Event Handling,我有一个按钮控件,我需要删除所有附加到其上的事件处理程序 那怎么可能呢 Button button = GetButton(); button.Click.RemoveAllEventHandlers(); 你不能,基本上-至少不能没有反思和大量的肮脏 事件严格来说是“订阅,取消订阅”-你不能取消订阅其他人的处理程序,就像你不能更改其他人对对象的引用一样。我在StackOverflow上找到了这个答案: 最初的海报发现: 注意:由于我发布原始答案的问题已结束,我将在此处交叉发布我答案的改进版

我有一个按钮控件,我需要删除所有附加到其上的事件处理程序

那怎么可能呢

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

你不能,基本上-至少不能没有反思和大量的肮脏


事件严格来说是“订阅,取消订阅”-你不能取消订阅其他人的处理程序,就像你不能更改其他人对对象的引用一样。

我在StackOverflow上找到了这个答案:

最初的海报发现:

注意:由于我发布原始答案的问题已结束,我将在此处交叉发布我答案的改进版本此答案仅适用于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);
}

Edit:我复制了,当没有订阅任何事件处理程序时,它会阻止方法抛出
NullReferenceException
。积分(和投票)应该在他们的答案上。

我有一个空错误问题,代码是杰米·迪克森(Jamie Dixon)在没有点击事件的情况下发布的

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

}

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

只是想稍微扩展一下道格拉斯的常规,我非常喜欢。 我发现我需要向eventHandlersStore添加额外的null检查,以处理传递的元素尚未附加任何事件的情况

/// <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);
}
//
///从指定元素中删除订阅指定路由事件的所有事件处理程序。
/// 
///定义路由事件的UI元素。
///要删除其事件处理程序的路由事件。
公共静态空隙清除器OutDeventhandler(UIElement元素,RoutedEvent RoutedEvent)
{
//获取EventHandlersStore实例,该实例保存指定元素的事件处理程序。
//EventHandlersStore类声明为内部。
var eventHandlersStoreProperty=typeof(UIElement).GetProperty(
“EventHandlersStore”,BindingFlags.Instance | BindingFlags.NonPublic);
对象eventHandlersStore=eventHandlersStoreProperty.GetValue(元素,null);
if(eventHandlersStore==null)返回;
//在EventHandlersStore实例上调用GetRoutedEventHandlers方法
//用于获取订阅的事件处理程序数组。
var getRoutedEventHandlers=eventHandlersStore.GetType().GetMethod(
“GetRoutedEventHandler”,BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var routedEventHandlers=(RoutedEventHandlerInfo[])getRoutedEventHandlers.Invoke(
eventHandlersStore,新对象[]{routedEvent});
//迭代地从元素中删除所有路由事件处理程序。
foreach(路由EventHandler中的变量routedEventHandler)
元素。RemoveHandler(routedEvent,routedEventHandler.Handler);
}

我正在处理WinForms项目,在该项目中,我必须从ToolStripMenuItem中删除click EventHandler,并将其替换为我自己的处理程序。(我必须修改单击上下文菜单项时采取的操作)

对我来说,来自user2113340的代码不起作用。为了使用ToolStripMenuItem,我不得不这样修改它:

    private void RemoveClickEvent(ToolStripMenuItem control)
    {
        FieldInfo eventClick = typeof(Control).GetField("EventClick", BindingFlags.NonPublic | BindingFlags.Static);
        PropertyInfo eventsProp = typeof(Component).GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
        EventHandlerList events = (EventHandlerList)eventsProp.GetValue(control, null);
        FieldInfo headInfo = events.GetType().GetField("head", BindingFlags.NonPublic | BindingFlags.Instance);
        object head = headInfo.GetValue(events);
        FieldInfo keyType = head.GetType().GetField("key", BindingFlags.NonPublic | BindingFlags.Instance);
        object key = keyType.GetValue(head);
        Delegate d1 = events[key];
        events.RemoveHandler(key, d1);
    }

不过这是具体实现的问题——答案出现在2008年,我甚至不想说它是否能在.NET4上运行。依赖这样的东西是一个非常糟糕的主意。谢谢,但是这一行总是返回null:typeof(Control).GetField(“EventClick”,BindingFlags.Static | BindingFlags.NonPublic);我实现了一个类似的解决方案,该解决方案使用EventHandlerList对象的几个内部方法。查看答案你能用MyButtonClass替换Button吗?我想更简单的方法是禁用Button我想在之后只添加一个事件处理程序,所以禁用不会有帮助。可能重复我知道这是一个非常老的问题,但我认为您可能应该将所选答案改为道格拉斯给出的反射选项。“你不能”是一个非常糟糕的答案,尤其是当有一个非常好的例子表明你现在可以的时候;取消订阅其他人的处理程序!我正在使用第三方的自定义按钮,并希望删除作者的单击事件处理程序…@William:基本上,如果不依赖实现细节和反射,就不能删除,除非自定义按钮公开此类行为。事件的封装是为了处理程序不会相互干扰。@William:1)您使用控件的方式不是为它设计的,因此很容易造成问题。2) 您的解决方案很可能在将来的版本中中断。3) 它在信任度低的环境中不起作用。基本上,你希望你的代码有多脆弱;考虑设计而不仅仅是实现。我已经创建了自己的自定义按钮,并从原始按钮复制了我需要的(图标等)。是否可以在silverlight中执行此操作?silverlight没有路由EventHandlerInfo。。。。是否可以将其扩展为扩展方法?那太好了。。。
/// <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);
}
    private void RemoveClickEvent(ToolStripMenuItem control)
    {
        FieldInfo eventClick = typeof(Control).GetField("EventClick", BindingFlags.NonPublic | BindingFlags.Static);
        PropertyInfo eventsProp = typeof(Component).GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
        EventHandlerList events = (EventHandlerList)eventsProp.GetValue(control, null);
        FieldInfo headInfo = events.GetType().GetField("head", BindingFlags.NonPublic | BindingFlags.Instance);
        object head = headInfo.GetValue(events);
        FieldInfo keyType = head.GetType().GetField("key", BindingFlags.NonPublic | BindingFlags.Instance);
        object key = keyType.GetValue(head);
        Delegate d1 = events[key];
        events.RemoveHandler(key, d1);
    }