动态删除事件处理程序的解决方案(使用反射)。有更好的方法吗?

问题描述 投票:0回答:1

我需要从从我没有代码的 dll 加载的控件中删除事件处理程序。由于似乎没有“官方”(即由 .NET Framework 的公共方法支持),因此我能够创建几个扩展方法,这些方法正是使用 Reflection 来完成此操作。

有关所有详细信息,请参阅此博客文章:使用反射从 WinForm ListView 控件中删除事件

这里是如何删除 SelectedIndexChanged 事件的代码示例(动态且无需访问原始处理程序)

//for a UserControl (in fact any control that implements System.ComponentModel.Component)
var userControl = new UserControl();
//we can get the current mapped event handlers
userControl.eventHandlers();
//its signature
userControl.eventHandlers_MethodSignatures();
//remove one by using the static field name
userControl.remove_EventHandler("EVENT_SELECTEDINDEXCHANGED");
//or use this one specifically mapped to the SelectedIndexChanged event
userControl.remove_Event_SelectedIndexChanged

我的问题是:“还有其他方法吗?”

虽然我的解决方案有效并且看起来稳定,但我正在进行内部 .NET 对象操作,所以也许有更好的解决方案(在 4.0 或 4.5 中)?

相关帖子:

c# reflection
1个回答
0
投票

可以使用以下代码从控制器中删除事件,它是一种扩展方法:

    public static void EventHandlersClear(this Control control, params string[] eventKeyNames)
    {
        if (eventKeyNames == null) return;
        if (eventKeyNames.Length == 0) return;

        var allEventFields = typeof(Control).GetFields(BindingFlags.Static | BindingFlags.NonPublic);
        var eventFields = allEventFields.Where(q => eventKeyNames.Contains(q.Name)).ToList();
        if (eventFields.Count == 0) return;

        var eventsProperty = control.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
        var events = (EventHandlerList)eventsProperty.GetValue(control, null);
        foreach (var eventKey in eventFields)
        {
            events.RemoveHandler(eventKey, events[eventKey]);
        }
    }

例如使用 .net Framework 4.8 创建一个 Windows 应用程序:

代码后面:

    private void ClearEventHandlersBTN_Click(object sender, EventArgs e)
    {
        button1.EventHandlersClear("EventClick", "EventMouseDown", "EventMouseClick");
        button2.EventHandlersClear("EventClick", "EventMouseDown", "EventMouseClick");
        button3.EventHandlersClear("EventClick", "EventMouseDown", "EventMouseClick");
    }
    private void button1_Click(object sender, EventArgs e)
    {
        MessageBox.Show("button1_Click");
    }
    private void button3_Click(object sender, EventArgs e)
    {
        MessageBox.Show("button3_Click");
    }

    private void button2_Click(object sender, EventArgs e)
    {
        MessageBox.Show("button2_Click");
    }
    private void button1_MouseClick(object sender, MouseEventArgs e)
    {
        MessageBox.Show("button1_MouseClick");
    }
    private void button2_MouseClick(object sender, MouseEventArgs e)
    {
        MessageBox.Show("button2_MouseClick");
    }
    private void button3_MouseClick(object sender, MouseEventArgs e)
    {
        MessageBox.Show("button3_MouseClick");
    }
    private void button3_MouseDown(object sender, MouseEventArgs e)
    {
        MessageBox.Show("button3_MouseDown");
    }
    private void button2_MouseDown(object sender, MouseEventArgs e)
    {
        MessageBox.Show("button3_MouseDown");
    }
    private void button1_MouseDown(object sender, MouseEventArgs e)
    {
        MessageBox.Show("button3_MouseDown");
    }

要使用此扩展方法,您需要知道控件类型中事件字段的名称。

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

typeof(Control).GetFields(BindingFlags.Static | BindingFlags.NonPublic)
© www.soinside.com 2019 - 2024. All rights reserved.