I'm trying to determine if an object has any event handlers registered on it. The reason I need this, is to not let an object to register one single event twice.
this .menu.BeforePopup += new CancelEventHandler(menu_BeforePopup); // OKthis.menu.BeforePopup += new CancelEventHandler(menu_BeforePopup); // Don't let it happen twice |
Any help would be great

How to find registered event handlers?
PeteB43
> FieldInfo fi = objType.GetField("Event"+eventName,All);
This depends on the naming convention used by the C# compiler for an event's backing delegate field. There's no guarantee that different compilers (or even different versions of the same compiler) will use the same name, and there might not even be a separate field for the event. So this is hardly a general purpose solution.
Jim Jiang
Jonas Lindstrom
>Couldn't you just query the InvoationList outisde as well, this would work:
No it wont, because ...
> Delegate.Combine(eventDelegate, delegateToHook);
you're throwing away the return value from Combine, and ...
> HookDelegate(button1.Click, clickHandler);
you're not allowed to use button1.Click in this context since it's an event and doesn't return a delegate.
C# Learner
Lol well yes you're correct about the combine but you're wrong about the Event, it is a delegate and returns a delegate. Event is just a nice little metadata about the delegate field. Just updated and runned this example, worked fine.
public static Delegate HookDelegate(Delegate eventDelegate, Delegate delegateToHook)
{
bool alreadyHoooked = false;
if (eventDelegate != null)
{
foreach (Delegate d in ((Delegate)eventDelegate).GetInvocationList())
{
if (d.Equals(delegateToHook))
{
alreadyHoooked = true;
break;
}
}
}
if (!alreadyHoooked)
eventDelegate = Delegate.Combine(eventDelegate, delegateToHook);
return eventDelegate;
}
In the class:
public static event EventHandler anEvent;
and in main:
anEvent = (EventHandler)HookDelegate(anEvent, new EventHandler(Do));
Although some refactoring is in place, conceptually this works.
rich2000
Couldn't you just query the InvoationList outisde as well, this would work:
public static void HookDelegate(Delegate eventDelegate, Delegate delegateToHook)
{
bool alreadyHoooked = false;
foreach (Delegate d in anEvent.GetInvocationList)
{
if (d.Target == delegateToHook.Target
&&
d.Method == delegateToHook.Method)
{
alreadyHoooked = true;
break;
}
}
if (!alreadyHoooked)
Delegate.Combine(eventDelegate, delegateToHook);
}
And then:
EventHandler clickHandler = new EventHandler(button_click);
HookDelegate(button1.Click, clickHandler);
Suraj Guptha
Indeed, that's a great code. Like Mattias said, there's an issue with GetField("Event"+eventName,All). For me, it seems that GetField(eventName,All) just works fine.
The second issue is
mi.Invoke(obj, new object[]{});
it always returns an empty EventHandlerList...
MSDev23
noobMe
noorbakhsh
but that looks like you need to know the name of the method that has been assigned to the event handler.
globalswtech
yes. . .
its a little difficult. . . I posted something on the newsgoups a while back. . .
took me a while to find it. had to get it from an archive.
NOTE: Talking to Juval Lowy he suggested there was something wrong with my model if I had to do this. He was right.
at any rate. . . here you go:
=====================================================
ArrayList eventData = new ArrayList();
EventDescriptorCollection events = TypeDescriptor.GetEvents(button1);
foreach (System.ComponentModel.EventDescriptor myEvent in events)
{
//Unwire the events
EventDatum ed = EventDatum.Create(button1, myEvent);
if (ed == null) continue;
EventData.Add(ed);
ed.Unwire(myComponent);
}
//Do something with button1 here . . .
// now rewire . . .
foreach(EventDatum ed in EventData)
if (ed != null)
ed.Wire(myComponent);
EventData.Clear();
=====================================
The utility class==========================
public class EventDatum
{
private EventDescriptor _eventDesc;
private Delegate _event;
private static MethodInfo GetEventsMethod(Type objType)
{
MethodInfo mi = objType.GetMethod("get_Events",All);
if ((mi ==null)& (objType.BaseType!=null))
mi = GetEventsMethod(objType.BaseType);
return mi;
}
private static EventHandlerList GetEvents(object obj)
{
MethodInfo mi = GetEventsMethod(obj.GetType());
if (mi == null) return null;
return (EventHandlerList) mi.Invoke(obj, new object[]{});
}
private static FieldInfo GetEventIDField(Type objType, string eventName)
{
FieldInfo fi = objType.GetField("Event"+eventName,All);
if ((fi ==null)& (objType.BaseType!=null))
fi = GetEventIDField(objType.BaseType, eventName);
return fi;
}
private static object GetEventID(object obj, string eventName)
{
FieldInfo fi = GetEventIDField(obj.GetType(), eventName);
if (fi ==null) return null;
return fi.GetValue(obj);
}
private static BindingFlags All
{
get
{
return
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance| BindingFlags.IgnoreCase|
BindingFlags.Static;
}
}
internal EventDatum(EventDescriptor desc, Delegate aEvent)
{
_eventDesc = desc;
_event = aEvent;
}
public static EventDatum Create(object obj, EventDescriptor desc)
{
EventHandlerList list = GetEvents(obj);
if (list==null) return null;
object key = GetEventID(obj, desc.Name);
if (key==null) return null;
Delegate evnt = list[key];
if (evnt == null) return null;
return new EventDatum(desc, evnt);
}
public void Wire(object obj)
{
_eventDesc.AddEventHandler(obj, _event);
}
public void Unwire(object obj)
{
_eventDesc.RemoveEventHandler(obj, _event);
}
}
SJLaing
tungdh
private CancelEventHandler _beforePopup;
public event CancelEventHandler BeforePopup
{
add
{
if (_beforePopup != null)
foreach (Delegate d in _beforePopup.GetInvocationList()
if (d.Equals(value)) return;
_beforePopup += value;
}
remove { _beforePopup -= value; }
}
Not foolproof because 'value' could be a multicast delegate itself, but it's a start.
SeanDraper
nwkrzysztf
Hi Patrik,
and what is here the "anEvent" Is it the event itself or the event handler I just can't call GetInvocationList() on any of events..