5

I need to remove event handlers from a control loaded from a dll that I don't have the code for. Since there doesn't seem to be an 'official' (i.e. supported by public methods of the .NET Framework), I was was able to create a couple extension methods that did exactly that using Reflection.

See this blog post for all the details: Removing an Event from a WinForm ListView control using reflection

Here is a code sample of how to remove the SelectedIndexChanged event (dynamically and without access to the original handler)

//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

My question is: "is there another way?"

Although my solution works and seems stable, I'm doing internal .NET objects manipulation, so maybe there is a better solution (in 4.0 or 4.5)?

Related posts:

Rizwan
  • 103
  • 4
  • 24
Dinis Cruz
  • 4,161
  • 2
  • 31
  • 49
  • If you don't know what the event handlers do, should you unbind them? – Jodrell Jun 14 '12 at 10:52
  • In this case I knew exactly what the event handlers where doing (and the fact that they were the root cause of an .NET exception that would happen on ListView item selection) – Dinis Cruz Jun 14 '12 at 16:34

1 Answers1

0

can use folowing codes for remove events from controller , its a extention method :

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

for example create a windows application with .net framework 4.8 :

enter image description here

behind code :

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

To use this extension method, you need to know the name of the events field in the control type.

Can use folowing code for get all event field names :

typeof(Control).GetFields(BindingFlags.Static | BindingFlags.NonPublic)
BQF
  • 33
  • 7