4

I'm trying to use a single event handler for several controls in an ASP.NET web page. I would like to add the event handler at runtime if and only if it doesn't already exist. In C#, I would write it as seen below:

if (myTextBox.OnTextChanged == null)
{
    myTextBox.OnTextChanged += DoTextChangingValidation;
}

Likewise, I know I can remove the event handler as follows:

if (myTextBox.OnTextChanged != null)
{
    myTextBox.OnTextChanged -= DoTextChangingValidation;
}

I know how to add and remove the event handler in Visual Basic... But how do I figure out how to check to see if it is already assigned?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Michael
  • 362
  • 1
  • 5
  • 11
  • The code that you've written wouldn't compile in C#. From outside a class, you can only do 2 things to an event: add a handler, or remove a handler. You cannot get the list of handlers, so `myTextBox.OnTextChanged` wouldn't be an expression that returns a delegate. Given that, it's not clear what you're actually doing in C#, and therefore what you want to do in VB. – Pavel Minaev Oct 28 '09 at 21:49
  • Okay, so I was mistaken on what I can & cannot do in C#. Basically what I am trying to do is prevent the same handler from being added to a control multiple times. I want to ensure that no more than 1 handler is ever assigned to the event at any given time. – Michael Oct 28 '09 at 22:21

2 Answers2

7

You cannot do that from outside the object, either in C# or in Visual Basic. An event is basically two accessors: add and remove. This is immediately visible if you hand-code it:

public event EventHandler Click
{
     add { ... }
     remove { ... }
}

These become add_Click(EventHandler) and remove_Click(EventHandler) methods. Even if you use the default event implementation,

public event EventHandler Click;

it's still no different, except that the accessors are generated for you with the default implementation, which uses a private multicast delegate field with the same name as the event to store those handlers.

This means two things:

  1. For clients of the class, the only two things they can do about an event is add or remove handlers, since only accessors are exposed. There's no accessor to list currently registered handlers

  2. Even if you use default implementation for events, which provides a field, that field is still private, so you can't access it except from inside a method of the same class. You can use reflection if you have code permission to do so, but see #1 for why it's not a general solution.

This is actually done on purpose. The reason is this: the object may be shared, and other code may have registered its handlers for its events. If you get access to list of handlers, you'd be able to call them yourself, potentially breaking the contract, and accessing private methods in a manner the owner of the class did not intend.

If you want this kind of thing, it needs to be done in the class providing the event - either write your own add and remove to check for dupes, or expose the private field via a property.

Pavel Minaev
  • 99,783
  • 25
  • 219
  • 289
3

You don't need to do the check in Visual Basic for this scenario. The normal remove syntax is smart enough not to throw an exception at you if it's already gone.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • Maybe the .net should thrown an exception if no more events are handled. What do you think? – Tony Jan 29 '11 at 12:41
  • 1
    @Tony - if you like that behavior, you can use C#. But take note of the problems it's caused for c# programmers - the extra code they have to write, all the incorrect (buggy) implementations out there, etc – Joel Coehoorn Jan 29 '11 at 20:05
  • It does throw a nullreferenceexception when you try to remove an not existing handler. – Sebastien Jan 14 '14 at 22:16