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

3

我正在编写一个WinForm应用程序。在form1中,我有一个panel,并且它有许多事件处理程序。当我dispose panel1并创建新面板时,以前的事件仍然存在并且会触发。为了移除panel1上的事件,我尝试使用以下代码。

panel1.Click -=  clickHandle_1 ; 

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


1
这是一个代码异味。您可以编写一个事件处理程序,为所有三个任务执行工作。或者简单地从Panel派生一个类,覆盖OnResize和OnClick方法。也不太清楚为什么要将它们删除,可以在事件处理程序中检查bool变量来跳过它正在做的事情。请尝试发布有意义的代码,而不是这样的代码。 - Hans Passant
同意。我会研究一下在这里应用策略模式的变种。http://www.oodesign.com/strategy-pattern.html - dcastro
4个回答

9

根据此处, 要取消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]);

如果要取消面板1的其他事件,请将 EventClick 更改为要删除的事件名称。

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

EventInfo[] info = type.GetEvents();
for (int i = 0; i < info.Length; i++)
{
   Console.WriteLine(info[i].Name + "\n");
}

1
+1 对于你在 静态私有字段 上的有趣 发现,你可能要搜索很多吧? - King King
2
你应该注明原始答案的来源 - https://dev59.com/LHVD5IYBdhLWcg3wGHiu#91853 - T.Todua

4

通常情况下,当你Dispose一个对象/控件时,该对象/控件的所有成员,包括事件处理程序列表,都应该被释放并且无法使用。因此,当你说你的panel1被disposed时,就不可能在该已释放的控件上触发任何事件(例如Resize)。你应该检查一下是否确实需要dispose你的panel。以下是一种使用Reflection来移除控件的所有事件处理程序Dispose它们(即类型为EventHandlerListEvents)的方法:

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并创建它的新实例时,当我调整面板大小时,之前的事件会被调用!!你可以测试一下! - AmirHossein Rezaei
@AmirHosseinRezaei,您能否发布一下您如何“Dispose”面板的代码? - King King

3

逐个删除它们:

panel1.Click -= clickHandle_1;

没有一种干净的方法可以一次性取消所有事件处理程序的订阅。请跟踪您正在订阅的内容并相应地取消订阅它们。


0

不确定这是否有效,但这是我最接近的结果:

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

}

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