如何在C#中删除并重新连接EventHandler到控件?

我读过这个答案 。 它只是告诉我如何从按钮控件中删除click事件。 我想知道如何更改代码(特别是GetField("EventClick"...部分!),所以我可以用其他控件做同样的事情。例如,我想删除TextBoxTextChanged事件。而我还想知道如何重新附加事件处理程序。

 public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void textBox1_TextChanged(object sender, EventArgs e) { if (textBox1.Text.Length < 10) return; MessageBox.Show("do something"); } private void Form1_Load(object sender, EventArgs e) { Tools.mkTextBoxWithPlaceholder(textBox1, "hi, input here..."); } } class Tools { public static void mkTextBoxWithPlaceholder(TextBox tb, string placeholder) { tb.Tag = placeholder; tb.GotFocus += new EventHandler(tb_GotFocus); tb.LostFocus += new EventHandler(tb_LostFocus); } private static void tb_GotFocus(object sender, EventArgs e) { TextBox tb = sender as TextBox; tb.Clear(); } private static void tb_LostFocus(object sender, EventArgs e) { TextBox tb = sender as TextBox; //TODO Remove the TextChanged event handler here. tb.Text = tb.Tag as string; //TODO Reattach the TextChanged event handler here. } } 

使用上面的代码,textBox1将具有像占位符这样的函数。也许你可以给我一些关于如何将占位符添加到文本框的帮助。 这就是我想要的。

根据我的这篇文章,这是你问题的解决方案。

这些辅助方法允许您操作特定控件的任何事件:

 // Also searches up the inheritance hierarchy private static FieldInfo GetStaticNonPublicFieldInfo(Type type, string name) { FieldInfo fi; do { fi = type.GetField(name, BindingFlags.Static | BindingFlags.NonPublic); type = type.BaseType; } while (fi == null && type != null); return fi; } private static object GetControlEventKey(Control c, string eventName) { Type type = c.GetType(); FieldInfo eventKeyField = GetStaticNonPublicFieldInfo(type, "Event" + eventName); if (eventKeyField == null) { if (eventName.EndsWith("Changed")) eventKeyField = GetStaticNonPublicFieldInfo(type, "Event" + eventName.Remove(eventName.Length - 7)); // remove "Changed" else eventKeyField = GetStaticNonPublicFieldInfo(type, "EVENT_" + eventName.ToUpper()); if (eventKeyField == null) { // Not all events in the WinForms controls use this pattern. // Other methods can be used to search for the event handlers if required. return null; } } return eventKeyField.GetValue(c); } private static EventHandlerList GetControlEventHandlerList(Control c) { Type type = c.GetType(); PropertyInfo pi = type.GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance); return (EventHandlerList)pi.GetValue(c, null); } 

然后您可以使用它们临时分离事件处理程序:

 private static void tb_LostFocus(object sender, EventArgs e) { TextBox tb = (TextBox)sender; var eventList = GetControlEventHandlerList(tb); var eventKey = GetControlEventKey(tb, "TextChanged"); // Remove the handlers var handlers = eventList[eventKey]; eventList.RemoveHandler(eventKey, handlers); // ... perform your task // Reattach the handlers eventList.AddHandler(eventKey, handlers); } 

如果你想知道这里到底发生了什么,请继续阅读。

Windows窗体使用EventHandlerList类来维护控件事件。 使用object类型的简单键访问每个事件。 密钥存储在控件的私有字段中。 访问此数据的唯一方法是使用reflection,但我们应该知道事件键字段的名称。 通过反编译Control类及其后代,我们可以看到键使用不同的名称。 我在密钥中提取了三种常见的命名模式,并在GetControlEventKey方法中使用它们。

这是WinForms控件用于保存事件处理程序的机制。 关于它没有什么特别之处。 这只是一个设计选择。

去掉

 Mybutton.event -= methodname; 

重新连接

 Mybutton.event += methodname;