删除特定控件的所有事件处理程序

Posted

技术标签:

【中文标题】删除特定控件的所有事件处理程序【英文标题】:remove all EventHandlers of a specific Control 【发布时间】:2013-09-17 09:43:32 【问题描述】:

我正在用 winForm 编写一个应用程序。我在 from1 中有一个面板,它有很多事件处理程序。 当我处理 panel1 并创建新面板时,以前的事件存在并且它们会触发。为了删除 panel1 事件,我尝试了下面的代码。

panel1.Click -=  clickHandle_1 ; 

但它并不适用于程序代码中的所有地方。例如在另一种方法中。 创建新 panel1 时如何删除 panel1 之前的所有事件?

【问题讨论】:

这是代码异味。您可以编写 one 事件处理程序来完成所有三个工作。或者只是从 Panel 派生一个覆盖 OnResize 和 OnClick 方法的类。也不清楚为什么要删除它们,可以在事件处理程序中检查一个 bool 变量以跳过它正在执行的任何操作。尝试发布有意义的代码而不是这个。 同意。我会考虑在这里应用策略模式的变体。 oodesign.com/strategy-pattern.html 【参考方案1】:

根据this, 要取消 panel1 的所有 点击事件,请执行以下操作:

FieldInfo f1 = typeof(Control).GetField("EventClick", BindingFlags.Static| BindingFlags.NonPublic);
object obj = f1.GetValue(panel1);
PropertyInfo pi = panel1.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
EventHandlerList list = (EventHandlerList)pi.GetValue(panel1, null);
list.RemoveHandler(obj, list[obj]);

为了取消 panel1 的其他事件,请将 EventClick 更改为您要删除的事件名称。

可以使用此代码获取所有事件名称:

EventInfo[] info = type.GetEvents();
for (int i = 0; i < info.Length; i++)

   Console.WriteLine(info[i].Name + "\n");

【讨论】:

+1 为static private fields 上有趣的discovery,您可能需要搜索很多? 你应该把原始答案的来源 - ***.com/a/91853/2377343【参考方案2】:

通常当您Dispose 一个对象/控件时,该对象/控件的所有成员(包括Event handler list)也应该被释放并且不可用。因此,当您说your panel1 is disposed 时,不可能在该已释放控件上触发任何事件(例如Resize)。 您应该检查您是否确实丢弃了您的面板。您可以使用以下方法删除控件的所有Event handlers,使用ReflectionDisposeEventsEventHandlerList 的类型):

public void RemoveHandlerList(Control c)
  EventHandlerList list = (EventHandlerList) typeof(Control).GetProperty("Events", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(c, null);
  typeof(EventHandlerList).GetMethod("Dispose").Invoke(list, null);

【讨论】:

并非不可能!我的意思是当我处理 panel1 并创建它的新实例时,当我调整面板大小时,之前的事件会调用!你可以测试! @AmirHosseinRezaei 你能发布代码来显示你如何Dispose你的面板吗?【参考方案3】:

一次删除一个:

panel1.Click -= clickHandle_1;

没有一次性取消订阅所有事件处理程序的干净方法。跟踪您订阅的内容并相应地取消订阅。

【讨论】:

【参考方案4】:

不确定这是否可行,但这是我最接近的:

public partial class Form1 : Form

    public Form1()
    
        InitializeComponent();
    


    private Dictionary<string, EventHandler> _handlers = new Dictionary<string, EventHandler>();
    TextBox _txt = new TextBox();

    void WireHandlers()
    

         // get references of your handlers
         EventHandler _hnd1 = delegate  return; ; // here will be your named method. This is only for example
         EventHandler _hnd2 = delegate  return; ; // here will be your named method. This is only for example

         // wire handlers
        _txt.Click += _hnd1;
        _txt.TextChanged  += _hnd2;
         // save wired handler collection
        _handlers.Add("Click", _hnd1);
        _handlers.Add("TextChanged", _hnd2);
    


    void UnwireHandlers()
    

        // lets unwire all handlers
        foreach (var kvp in _handlers)
        
            // inspect keyValuePair - each key corresponds to the name of some event
            switch (kvp.Key)
            
                case "Click":
                    _txt.Click -= kvp.Value;
                    break;
                case "TextChanged":
                    _txt.TextChanged  -= kvp.Value;
                    break;
                default:
                    throw new Exception("no such handler found");
            
        

        _handlers.Clear();
    


【讨论】:

以上是关于删除特定控件的所有事件处理程序的主要内容,如果未能解决你的问题,请参考以下文章

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

如何删除“按钮”的“单击”事件的所有事件处理程序?

从自定义控件的模板部分中删除事件处理程序

如何删除事件处理程序并将其重新附加到 c# 中的控件?

多个控件的事件处理程序 vb.net

如何在 MFC CDialog 类中自动删除事件处理程序?