如何在c#中移除和重新附加EventHandler到控件

本文关键字:新附加 EventHandler 控件 | 更新日期: 2023-09-27 18:11:06

我已经看过这个答案了。它只是告诉我如何从按钮控件中删除点击事件。我想知道如何更改代码(特别是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将有一个类似占位符的函数。也许你可以给我一些关于如何添加占位符到文本框的帮助。这就是我想要的

如何在c#中移除和重新附加EventHandler到控件

删除

Mybutton.event -= methodname;

再植

Mybutton.event += methodname;

根据我的这篇文章,这里有一个解决你问题的方法。

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

// 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类型的简单键访问每个事件。键存储在控件的私有字段中。访问该数据的唯一方法是使用反射,但是我们应该知道事件键字段的名称。通过反编译Control类及其后代,我们可以看到键使用不同的名称。我提取了键之间三种常见的命名模式,并在GetControlEventKey方法中使用。

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