How to invoke a custom event in a derived control?

D

Dan Soendergaard

Hello fellow developers,

I've created a control which derives from the .NET TextBox. I then
wanted to add two events to the new control, so I added the following
to the control code:

public event EventHandler InvalidValueMatched;
public event EventHandler ValidValueMatched;

But when one of the events is raised I get this exception:

System.NullReferenceException was unhandled by user code
Message="Object reference not set to an instance of an object."
Source="UserResponseControl"
StackTrace:
at
CustomControls.ValidationTextBox.OnValidating(CancelEventArgs e)
at
System.Windows.Forms.Control.PerformControlValidation(Boolean
bulkValidation)
at
System.Windows.Forms.ContainerControl.ValidateThroughAncestor(Control
ancestorControl, Boolean preventFocusChangeOnError)

By the way, I raise an event with the following code:
InvalidValueMatched.Invoke(this, new EventArgs());

How can this problem be solved? I have googled a lot, but none of the
tutorials/samples I can find, matches my scenario. Since I'm also
pretty new to custom controls, I'd like to know if I'm doing anything
wrong (ex. can I just pass a new EventArgs()?).

Thanks in advance!

- Dan
 
L

Larry Smith

Hello fellow developers,
I've created a control which derives from the .NET TextBox. I then
wanted to add two events to the new control, so I added the following
to the control code:

public event EventHandler InvalidValueMatched;
public event EventHandler ValidValueMatched;

But when one of the events is raised I get this exception:

System.NullReferenceException was unhandled by user code
Message="Object reference not set to an instance of an object."
Source="UserResponseControl"
StackTrace:
at
CustomControls.ValidationTextBox.OnValidating(CancelEventArgs e)
at
System.Windows.Forms.Control.PerformControlValidation(Boolean
bulkValidation)
at
System.Windows.Forms.ContainerControl.ValidateThroughAncestor(Control
ancestorControl, Boolean preventFocusChangeOnError)

By the way, I raise an event with the following code:
InvalidValueMatched.Invoke(this, new EventArgs());

How can this problem be solved? I have googled a lot, but none of the
tutorials/samples I can find, matches my scenario. Since I'm also
pretty new to custom controls, I'd like to know if I'm doing anything
wrong (ex. can I just pass a new EventArgs()?).

Thanks in advance!

It looks like no client has subscribed to your event. Fixing that will
likely fix the problem but you need to check "InvalidValueMatched" for null
before invoking it anyway. Moreover, it should be called inisde a try/catch
block since the event client (sink object) might throw an exception which
you'll want to catch and often (usually) ignore. The situation actually runs
deeper however since you'll probably want to continue firing your event to
any remaining clients. That is, just because one client throws an exception
doesn't mean you should stop firing to any remaining clients. I suggest
getting hold of a copy of "Programming .NET Components" by Juval Lowy. A
recognized .NET expert by MSFT (which becomes clear once you start reading
it), he goes into great detail on the subject, covering everything you'll
ever want to know. It's well worth the money even for experienced
developers.
 
D

Dan Soendergaard

It looks like no client has subscribed to your event. Fixing that will
likely fix the problem but you need to check "InvalidValueMatched" for null
before invoking it anyway. Moreover, it should be called inisde a try/catch
block since the event client (sink object) might throw an exception which
you'll want to catch and often (usually) ignore. The situation actually runs
deeper however since you'll probably want to continue firing your event to
any remaining clients. That is, just because one client throws an exception
doesn't mean you should stop firing to any remaining clients. I suggest
getting hold of a copy of "Programming .NET Components" by Juval Lowy. A
recognized .NET expert by MSFT (which becomes clear once you start reading
it), he goes into great detail on the subject, covering everything you'll
ever want to know. It's well worth the money even for experienced
developers.

Great, it works now! I'll have a look at the book as soon as possible.
I just have one more question: you suggest that I should invoke the
event inside a try/catch block, I can completely understand this. But,
isn't it bad practice to "ignore" an exception? Should I just leave
the catch-block empty and forget about the exception?

Thanks again!

- Dan
 
L

Larry Smith

Great, it works now! I'll have a look at the book as soon as possible.
I just have one more question: you suggest that I should invoke the
event inside a try/catch block, I can completely understand this. But,
isn't it bad practice to "ignore" an exception? Should I just leave
the catch-block empty and forget about the exception?

Only you know for sure in your particular app but generally speaking you
should strive to ignore it if possible. The reason is straight-forward
enough. The (source) object firing the event usually isn't tightly coupled
with its clients so it normally doesn't know who the clients (sink objects)
of the event are. The source object just fires the event to all interested
parties and that's all. If a particular sink object throws an exception, the
source object might not know how to deal with the problem. It may not know
who the clients even are (especially if its a generic object dealing with
external clients) nor what exceptions they might throw nor how to handle
them (which will vary from client-to-client). Imagine if your own app
registered for an event with a DB server for instance (one serving other
potential clients). What should that server do if you throw an exception. It
should catch it for sure because it shouldn't crash. It should also continue
firing the event to other clients. It really can't deal with your exception
however except gracefully back out of what it's doing and perhaps log it as
a courtesy for you. It shouldn't really be responsible for your program's
errors however so exceptions shouldn't normally be propagated back in the
first place. You should usually prevent it that is. Within your own app of
course you can always do whatever's appropriate however. The source object
might want to log the error, abort the app or whatever but other clients may
be waiting for the event to be fired so it might perilous to ignore them
(or, depending on your app, maybe they'll now have a problem given that the
other client failed). The looser the coupling is between source and sink
objects, the better your program will be.
 
D

Dan Soendergaard

Only you know for sure in your particular app but generally speaking you
should strive to ignore it if possible. The reason is straight-forward
enough. The (source) object firing the event usually isn't tightly coupled
with its clients so it normally doesn't know who the clients (sink objects)
of the event are. The source object just fires the event to all interested
parties and that's all. If a particular sink object throws an exception, the
source object might not know how to deal with the problem. It may not know
who the clients even are (especially if its a generic object dealing with
external clients) nor what exceptions they might throw nor how to handle
them (which will vary from client-to-client). Imagine if your own app
registered for an event with a DB server for instance (one serving other
potential clients). What should that server do if you throw an exception. It
should catch it for sure because it shouldn't crash. It should also continue
firing the event to other clients. It really can't deal with your exception
however except gracefully back out of what it's doing and perhaps log it as
a courtesy for you. It shouldn't really be responsible for your program's
errors however so exceptions shouldn't normally be propagated back in the
first place. You should usually prevent it that is. Within your own app of
course you can always do whatever's appropriate however. The source object
might want to log the error, abort the app or whatever but other clients may
be waiting for the event to be fired so it might perilous to ignore them
(or, depending on your app, maybe they'll now have a problem given that the
other client failed). The looser the coupling is between source and sink
objects, the better your program will be.

I can see it now, great explanation! Thanks again!

- Dan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top