If you just want to verify in the debugger that the event handler was added, you can cast the event to a System.Delegate
and look at the invocation list. This can be done for instance in the Visual Studio Immediate Window. Here I am examining the invocation list of an event called "MyEvent", which turns out to have 3 handlers added:
((System.Delegate)MyEvent).GetInvocationList()
{System.Delegate[3]}
[0]: {Method = {Void handler11_MessageReceived(System.Object, MyProject.MyEventArgs)}}
[1]: {Method = {Void handler21_MessageReceived(System.Object, MyProject.MyEventArgs)}}
[2]: {Method = {Void handler21_MessageReceived(System.Object, MyProject.MyEventArgs)}}
You can also browse the invocation list in the Watch window.
It might even be useful to do this if you are unsure whether some event listeners had been properly disposed of later, for example.
Update: How to check programmatically that one event contains another.
Checking programmatically that an event handler has been added to an event is more complex than one might imagine, because events are actually a form of MulticastDelegate. A multicast delegate can be either an "atomic" delete created by (e.g.) a delegate statement or lambda expression, or a combined delegate created by adding together two or more multicast delegates. And as it turns out, when one combined delegate is added to or subtracted from a second, what actually happens is that its invocation list is added to or subtracted from another. E.g.
Action a = () => Console.WriteLine("a");
Action b = () => Console.WriteLine("b");
Action c = () => Console.WriteLine("c");
Action d = () => Console.WriteLine("d");
var ab = a + b;
var cd = c + d;
var ad = a + d;
var bc = b + c;
var abcd = ab + cd;
var adbc = ad + bc;
var abc = abcd - d;
var bcd = abcd - a;
bool test1 = (abcd == (a + b + c + d)); // returns true
bool test2 = abcd.GetInvocationList().Contains(a); // returns true;
bool test3 = abcd.GetInvocationList().Contains(ab); // returns **false**;
bool test4 = abc.GetInvocationList().Contains(d); // returns false
If you want to create a public static extension method to check to see whether your handler was added to an event, it should correctly handle the case of a multicast delegate being added. But, does that just mean that the event has all the delegates of the handler? Or do they need to be bound together in sequence, since Delegate.Combine does preserve order? The following extension method checks for the latter:
public static class EventHelper
{
/// <summary>
/// Return true if all the atomic delegates in the multicast delegate handler are bound into the
/// publisher, grouped together and in the same order.
/// </summary>
/// <param name="publisher"></param>
/// <param name="handler"></param>
/// <returns></returns>
public static bool HasBound(this Delegate publisher, Delegate handler)
{
if (publisher == null || handler == null)
return false;
if (publisher == handler)
return true;
var publisherList = publisher.GetInvocationList();
var handlerList = handler.GetInvocationList();
return (publisherList.SublistIndex(handlerList, 0) >= 0);
}
public static bool HasBound<TEventArgs>(this EventHandler<TEventArgs> publisher, EventHandler<TEventArgs> handler) where TEventArgs : EventArgs
{
return HasBound((Delegate)publisher, (Delegate)handler);
}
public static bool HasBound(this EventHandler publisher, EventHandler handler)
{
return HasBound((Delegate)publisher, (Delegate)handler);
}
}
public static class ListHelper
{
public static int SublistIndex<T>(this IList<T> list, IList<T> sublist, int start)
{
var comparer = EqualityComparer<T>.Default;
for (int listIndex = start, end = list.Count - sublist.Count + 1; listIndex < end; listIndex++)
{
int count = 0;
while (count < sublist.Count && comparer.Equals(sublist[count], list[listIndex + count]))
count++;
if (count == sublist.Count)
return listIndex;
}
return -1;
}
}
And here are the results of testing:
bool test08 = a.HasBound(a); // returns true;
bool test09 = b.HasBound(a); // returns true;
bool test10 = abcd.HasBound(a + b + c + d); // returns true;
bool test11 = abcd.HasBound(adbc); // returns false - wrong order.
bool test12 = abcd.HasBound(a); // returns true;
bool test13 = cd.HasBound(a); // return false
bool test14 = bcd.HasBound(bc); // returns true despite the fact that bcd was not created directly from bc.
bool test15 = abcd.HasBound(ad); // returns false because the "ad" events are not adjacent in abcd.
Honestly, I would not do this outside of debugging however. Actually coding a check to see if a listener is bound to an event seems wrong.
Update 2 Is the real question here how to fetch all the event handlers from a Microsoft UIElement? It has to be done through some nasty reflection that isn't guaranteed to work in future .Net versions, as is shown here: How to remove all Click event handlers? and here: How would it be possible to remove all event handlers of the 'Click' event of a 'Button'?.