Has an Event Handler Already Been Added

Has an event handler already been added?

From outside the defining class, as @Telos mentions, you can only use EventHandler on the left-hand side of a += or a -=. So, if you have the ability to modify the defining class, you could provide a method to perform the check by checking if the event handler is null - if so, then no event handler has been added. If not, then maybe and you can loop through the values in
Delegate.GetInvocationList. If one is equal to the delegate that you want to add as event handler, then you know it's there.

public bool IsEventHandlerRegistered(Delegate prospectiveHandler)
{
if ( this.EventHandler != null )
{
foreach ( Delegate existingHandler in this.EventHandler.GetInvocationList() )
{
if ( existingHandler == prospectiveHandler )
{
return true;
}
}
}
return false;
}

And this could easily be modified to become "add the handler if it's not there". If you don't have access to the innards of the class that's exposing the event, you may need to explore -= and +=, as suggested by @Lou Franco.

However, you may be better off reexamining the way you're commissioning and decommissioning these objects, to see if you can't find a way to track this information yourself.

How to verify that an event handler has been added

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'?.

Check if a specific event handler method already attached


No. You cannot.

The event keyword was explicitly invented to prevent you from doing what you want to do. It makes the delegate object for the event inaccessible so nobody can mess with the events handlers.

Source : How to dermine if an event is already subscribed

Check to see if an event handler is attached to and event

You can implement a class inherited from EventHandler. For this class you can implement any additional behavior you want. For instance, you can create a collection which will hold object-event maps and you can implement a method which searches for a given pair or pattern.

c# event handler being added twice

I think the following demonstrates the scenario and does indeed fire twice, also propose a simple change (commented code) to the Init method that should fix the behavior. (Not thread safe btw, additional locks would be required)

[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var counter = 0;
var ts = new ThreadStart(() =>
{

Foo.Fired += (o, e) =>
{
counter++;
};
Foo.InitialiseTimer();
Foo.InitialiseTimer();
});
var t = new Thread(ts);
t.Start();

Thread.Sleep(30);
Assert.AreEqual(1, counter);
}
}

public class Foo
{
private static System.Timers.Timer TheTimer = null;

public static event EventHandler Fired;

public static void InitialiseTimer()
{
//if (TheTimer != null)
//{
// TheTimer.Stop();
// TheTimer = null;
//}
TheTimer = new System.Timers.Timer();
TheTimer.Interval = 10;
TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
TheTimer.AutoReset = false;
TheTimer.Start();
}

public static void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Do stuff in here
if (Fired != null)
{
Fired(null, null);
}
}
}

Check if a method is already registered to an event


In order to call CheckOnSomething, I need to pass a delegate to CatchSomething. Do I have to define a new delegate for that, or is there already something I can use ?

You could pass CatchSomething directly:

if (!o.CheckOnSomething(CatchSomething))
o.OnSomething += CatchSomething;

But you would need to update CheckOnSomething to accept a specific delegate type, so that CatchSomething can be converted:

public bool CheckOnSomething(Action<object, string> handler)
=> this.OnSomething.IsRegistered(handler);

This improves type-safety also, because only delegates with the correct signature can now be passed.

If I define a new delegate, will the delegate equality work ? The documentation says it checks for the delegate type, but since I pass the method directly, isn't a new delegate type created on the fly, which would make the equality always return false ?

Passing the method creates a new delegate instance not a new delegate type; the delegate type will always be Action<object, string>.

However, delegate equality relies on target as well as type, so passing CatchSomething will only be considered equal if it is form the same instance.

For example:

var obj1 = new Object1();
var instance1 = new Object2(obj1);

// Creates a delegate instance:
Action<object, string> catchSomething = instance1.CatchSomething;

catchSomething == instance1.CatchSomething; // true

var instance2 = new Object2(obj1);

catchSomething == instance2.CatchSomething; // false

Run code after the caller of the event handler has exited

You can only do this if you subclass SomeControl and override OnMouseDoubleClick like this:

class MyControl:SomeControl
{
void override OnMouseDoubleClick(MouseEventArgs e)
{
base.OnMouseDoubleClick(e)
//call event handlers
//Do X
}
}

You could even go as far as defining a new event AfterMouseDoubleClick and fire that event instead of calling X in OnMouseDoubleClick.

class MyControl:SomeControl
{
public event MouseButtonEventHandler AfterMouseDoubleClick;

void override OnMouseDoubleClick(MouseEventArgs e)
{
base.OnMouseDoubleClick(e)
//call event handlers
OnAfterMouseDoubleClick(e)
}

void virtual OnAfterMouseDoubleClick(MouseEventArgs e)
{
if(AfterMouseDoubleClick != null)
AfterMouseDoubleClick(this, e)
}
}

However you should really consider what you are doing in X to mess up Y.

Check if event has any listeners?

Assume the class is in a 3rd party library and it can't be modified:

    public class Data
{
public event EventHandler OnSave;
//other members
}

In your program:

    Data d = new Data();
d.OnSave += delegate { Console.WriteLine("event"); };
var handler = typeof(Data).GetField("OnSave", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(d) as Delegate;

if (handler == null)
{
//no subscribers
}
else
{
var subscribers = handler.GetInvocationList();
//now you have the subscribers
}

Check if an element has event listener on it. No jQuery

There is no JavaScript function to achieve this. However, you could set a boolean value to true when you add the listener, and false when you remove it. Then check against this boolean before potentially adding a duplicate event listener.

Possible duplicate: How to check whether dynamically attached event listener exists or not?

Find what event handler has been assigned to an event on an object WPF


  1. create a new WPF app
  2. put a treeview named "tree1" in your mainwindow
  3. copy-paste the code which follows to see it in action

Basically, you need to inherit TreeViewItem and build a mechanism to keep track of which handlers is being added to which node: event has no information about registered handlers for you to retrieve, unfortunately.

You're also going to need to rely exclusively on your new inheritance to build nodes, for things to work properly. That means, you must no longer refer to TreeViewItem, but have to refer to TreeNode (this is the name I chose for the custom class, feel free to change it).

Promised code is below, what it does is adding a "rootNode" node to the tree, which upon expansion would create a sibling node, which would have the same handler brought over to itself (so it too would create a sibling upon expansion, and so on).

namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();

TreeNode root = new TreeNode();
root.Header = "root";

tree1.Items.Clear();

// add node to tree before adding handlers, or you'll get
// a StackOverflowException
tree1.Items.Add(root);

root.AddHandler(TreeNode.ExpandedEvent, new RoutedEventHandler(expandedHandler));

}

private void expandedHandler(object sender, RoutedEventArgs e) { newNodeCopyExpandedHandlers(sender as TreeNode); }

private void newNodeCopyExpandedHandlers(TreeNode node)
{
TreeNode newNode = new TreeNode();
newNode.Header = "nuovo!";

// add node to tree before adding handlers, or you'll get
// a StackOverflowException
tree1.Items.Add(newNode);

foreach (Delegate d in newNode.GetHandlers(node, TreeNode.ExpandedEvent))
newNode.AddHandler(TreeNode.ExpandedEvent, d);
}
}

public class TreeNode : TreeViewItem
{
private Dictionary<RoutedEvent, List<Delegate>> handlersList = new Dictionary<RoutedEvent, List<Delegate>>();

public new void AddHandler(RoutedEvent e, Delegate d)
{
if (!handlersList.ContainsKey(e)) handlersList.Add(e, new List<Delegate>());
handlersList[e].Add(d);

base.AddHandler(e, d);
}
public new void RemoveHandler(RoutedEvent e, Delegate d)
{
if (!handlersList.ContainsKey(e)) handlersList.Add(e, new List<Delegate>());
if (handlersList[e].Contains(d)) handlersList[e].Remove(d);

base.RemoveHandler(e, d);
}

public List<Delegate> GetHandlers(TreeNode n, RoutedEvent e)
{
if (n.handlersList.ContainsKey(e)) return n.handlersList[e];
else return null;
}
}
}


Related Topics



Leave a reply



Submit