Removing Handler... URGENT
-
Hi, To remove Event Handlers from my all controls in the form, I want to use a generic code as follows. 1) Run through all controls in the Form 2) Run through all Events of a control using Reflection .GetEvents() 3) For each Event, I want to get the Delegate, so that I can remove all using GetInvocationList(). but .NET doesn't provide any property to get delegate for the Event Handler. Please help. How can I get the Delegate for the Event Handler.
-
Hi, To remove Event Handlers from my all controls in the form, I want to use a generic code as follows. 1) Run through all controls in the Form 2) Run through all Events of a control using Reflection .GetEvents() 3) For each Event, I want to get the Delegate, so that I can remove all using GetInvocationList(). but .NET doesn't provide any property to get delegate for the Event Handler. Please help. How can I get the Delegate for the Event Handler.
The
EventInfo
contains information about an event, which describesadd
andremove
accessors. It also has a method to remove an event handler,EventInfo.RemoveEventHandler
. In order to call this you must get the delegate for the event handler (the target method). To do this you need to get the field corresponding to the event that is the delegate. By default in C# at least, that field has the same name as the event. So, you can useEventInfo.Name
then callType.GetField
with the name and the rightBindingFlags
. Cast the field value toDelegate
and then you can get the invocation list, i.e. each target added to the delegate (a multicast delegate). Below is a quick sample I threw together.using System;
using System.Reflection;
class Test
{
public event EventHandler TestEvent;
public static void Main(string[] args)
{
Test t = new Test();
Console.WriteLine("Adding event handlers");
for (int i = 0; i < 5; i++)
{
t.TestEvent += new EventHandler(new Test(i).OnTestEvent);
Console.WriteLine("Added event handler to test " + i);
}
Console.WriteLine("Calling event");
if (t.TestEvent != null)
{
t.TestEvent(t, EventArgs.Empty);
}
Console.WriteLine("Removing event handlers");
RemoveAllHandlers(t);
Console.WriteLine("Calling event again");
if (t.TestEvent != null)
{
t.TestEvent(t, EventArgs.Empty);
}
}
Test()
{
}
int index = 0;
Test(int index)
{
this.index = index;
}
void OnTestEvent(object sender, EventArgs e)
{
Console.WriteLine("Handled from test " + index);
}
static void RemoveAllHandlers(Test test)
{
Type t = test.GetType();
foreach (EventInfo ei in t.GetEvents())
{
// Assumes compiler-generated events.
FieldInfo fi = t.GetField(ei.Name, BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance);
if (fi != null)
{
Delegate d = (Delegate)fi.GetValue(test);
foreach (Delegate handler in d.GetInvocationList())
{
Test target = handler.Target as Test;
if (target != null)
{
Console.WriteLine("Removing event handler from test " + target.index);
}
ei.RemoveEventHandler(test, handler);
}
}
}
}
} -
The
EventInfo
contains information about an event, which describesadd
andremove
accessors. It also has a method to remove an event handler,EventInfo.RemoveEventHandler
. In order to call this you must get the delegate for the event handler (the target method). To do this you need to get the field corresponding to the event that is the delegate. By default in C# at least, that field has the same name as the event. So, you can useEventInfo.Name
then callType.GetField
with the name and the rightBindingFlags
. Cast the field value toDelegate
and then you can get the invocation list, i.e. each target added to the delegate (a multicast delegate). Below is a quick sample I threw together.using System;
using System.Reflection;
class Test
{
public event EventHandler TestEvent;
public static void Main(string[] args)
{
Test t = new Test();
Console.WriteLine("Adding event handlers");
for (int i = 0; i < 5; i++)
{
t.TestEvent += new EventHandler(new Test(i).OnTestEvent);
Console.WriteLine("Added event handler to test " + i);
}
Console.WriteLine("Calling event");
if (t.TestEvent != null)
{
t.TestEvent(t, EventArgs.Empty);
}
Console.WriteLine("Removing event handlers");
RemoveAllHandlers(t);
Console.WriteLine("Calling event again");
if (t.TestEvent != null)
{
t.TestEvent(t, EventArgs.Empty);
}
}
Test()
{
}
int index = 0;
Test(int index)
{
this.index = index;
}
void OnTestEvent(object sender, EventArgs e)
{
Console.WriteLine("Handled from test " + index);
}
static void RemoveAllHandlers(Test test)
{
Type t = test.GetType();
foreach (EventInfo ei in t.GetEvents())
{
// Assumes compiler-generated events.
FieldInfo fi = t.GetField(ei.Name, BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance);
if (fi != null)
{
Delegate d = (Delegate)fi.GetValue(test);
foreach (Delegate handler in d.GetInvocationList())
{
Test target = handler.Target as Test;
if (target != null)
{
Console.WriteLine("Removing event handler from test " + target.index);
}
ei.RemoveEventHandler(test, handler);
}
}
}
}
}Thanks Heath for your help. I got it what you explained but when I try that with this sample code, it didn't work. Please help me. Yoour help is appreciated. I have a TextBox "textBox1" in my windows form. I have a handler for TextChanged event. I am trying to remove this using this code. but it doesn't work. Please help.
foreach(EventInfo ev in textBox1.GetType().GetEvents()) { FieldInfo fi = textBox1.GetType().GetField(ev.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (fi != null) { Delegate d = (Delegate)fi.GetValue(textBox1); foreach(Delegate handler in d.GetInvocationList()) { ev.RemoveEventHandler(this, handler); } } }
-
Thanks Heath for your help. I got it what you explained but when I try that with this sample code, it didn't work. Please help me. Yoour help is appreciated. I have a TextBox "textBox1" in my windows form. I have a handler for TextChanged event. I am trying to remove this using this code. but it doesn't work. Please help.
foreach(EventInfo ev in textBox1.GetType().GetEvents()) { FieldInfo fi = textBox1.GetType().GetField(ev.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (fi != null) { Delegate d = (Delegate)fi.GetValue(textBox1); foreach(Delegate handler in d.GetInvocationList()) { ev.RemoveEventHandler(this, handler); } } }
Most - if not all - of the Windows Forms controls provided by the .NET Framework do not use the event name as the field name. Please use ildasm.exe installed with the .NET Framework SDK to see what the fields are. Take the
add_TextChanged
method (theadd
accessor method for theControl.TextChanged
event):.method public hidebysig specialname instance void
add_TextChanged(class [mscorlib]System.EventHandler 'value') cil managed
{
// Code size 18 (0x12)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance class [System]System.ComponentModel.EventHandlerList [System]System.ComponentModel.Component::get_Events()
IL_0006: ldsfld object System.Windows.Forms.Control::EventText
IL_000b: ldarg.1
IL_000c: callvirt instance void [System]System.ComponentModel.EventHandlerList::AddHandler(object,
class [mscorlib]System.Delegate)
IL_0011: ret
} // end of method Control::add_TextChangedYou can use ildasm.exe (or an application like .NET Reflector that can also decompile source code) to view the
System.ComponentModel.EventHandlerList, System
type. This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Customer Product-lifecycle Experience Microsoft [My Articles] [My Blog] -
Most - if not all - of the Windows Forms controls provided by the .NET Framework do not use the event name as the field name. Please use ildasm.exe installed with the .NET Framework SDK to see what the fields are. Take the
add_TextChanged
method (theadd
accessor method for theControl.TextChanged
event):.method public hidebysig specialname instance void
add_TextChanged(class [mscorlib]System.EventHandler 'value') cil managed
{
// Code size 18 (0x12)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance class [System]System.ComponentModel.EventHandlerList [System]System.ComponentModel.Component::get_Events()
IL_0006: ldsfld object System.Windows.Forms.Control::EventText
IL_000b: ldarg.1
IL_000c: callvirt instance void [System]System.ComponentModel.EventHandlerList::AddHandler(object,
class [mscorlib]System.Delegate)
IL_0011: ret
} // end of method Control::add_TextChangedYou can use ildasm.exe (or an application like .NET Reflector that can also decompile source code) to view the
System.ComponentModel.EventHandlerList, System
type. This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Customer Product-lifecycle Experience Microsoft [My Articles] [My Blog]Thanks a lot for your help. But when I checked it in ILDASM, I found that each control uses different standards. For e.g. for SelectedIndexChanged has a filed called EVENT_SELECTEDCHANGED. So the generic code that I am thinking of may not work properly. Pls advise.
-
Thanks a lot for your help. But when I checked it in ILDASM, I found that each control uses different standards. For e.g. for SelectedIndexChanged has a filed called EVENT_SELECTEDCHANGED. So the generic code that I am thinking of may not work properly. Pls advise.
A better question would be, what are you trying to do anyway? There may be better ways to solve your problem. For example, if you don't want event handlers to fire under a certain condition, use a state variable and don't run all or the brunt of your event handler code if that state variable is set. If you have a lot of code to synchronize you might use
Monitor.TryEnter
against a singleton used by the entire application. This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Customer Product-lifecycle Experience Microsoft [My Articles] [My Blog]