Sunday, March 28, 2010

Custom Events

UPDATE: I've updated my examples below, and added to some of the text, to take into account tergiver's suggestion, in his comment below, that I should probably use the generic EventHandler delegate (introduced in .NET 2.0) rather than defining custom delegates (which dates back to .NET 1.x). In fact, I've totally taken out the custom delegate code, since I doubt many people are still using .NET 1.1 anymore. If anyone reading this who is not using .NET 2.0 and higher would like to know about the custom delegate declarations and usage, let me know in a comment.

I tend to write introductory topics in my blog. Not always, but typically. And not because I’m a newcomer to .NET (I’ve been using .NET since the beginning of 2002), but because all the complicated topics seem to be covered by everyone else and I think there is still a need to address simpler topics.

Today’s topic is no different. Even though writing custom events isn’t all that complicated, I still see a lot of questions on the Forums asking how to do it. So, let’s get to it.

Say you have a custom UserControl that you need to have raise an event when, for example, a user types "FOO" in a textbox that is on the Control.

Minimally, in your UserControl, you need the following things:

// First you must specify the event that you will be raising:

public event EventHandler MyFooBar;

// Then, when you need to fire the event in your UserControl, do this:
if (this.MyTextBox.Text == "FOO")
this.OnMyFooBar(new EventArgs());

// Lastly, this raises the MyFooBar event:
protected virtual void OnMyFooBar(EventArgs e)
{
if (MyFooBar != null)
MyFooBar(this, e);
}

Then, in your form, you just set up the usual delegates and EventHandlers:

this.oMyControl.MyFooBar += new System.EventHandler(this.oMyControl_MyFooBarHandler);

private void oMyControl_MyFooBarHandler(object sender, System.EventArgs e)
{
// whatever your form code needs to be, such as:
MessageBox.Show("FOO was specified!");
}

Or, the alternative way to do this since anonymous methods were introduced in 2.0:

this.oMyControl.MyFooBar += delegate
{
// whatever your code needs to be, such as
MessageBox.Show("FOO was specified!");
};

You can even get more fancy, creating custom EventArgs and utilizing generic delegates, but the above code is sufficient for simple things, when just the built-in System.EventArgs is all you need. For fancier, custom stuff, try this:

First, custom event args something like this:

public class MyCustomEventArgs : EventArgs 
{
public bool IsBarSpecified { get; set; }
}

Your UserControl code then gets changed to this:

// Change the event so that it can be handled by a generic delegate

public event EventHandler<MyCustomEventArgs> MyFooBar;

// Firing the event gets changed to something like this:
if (this.MyTextBox.Text.ToUpper().Contains("FOO"))
{
MyCustomEventArgs e = new MyCustomEventArgs();
if (this.MyTextBox.Text.ToUpper().Contains("BAR"))
e.IsBarSpecified = true;
else
e.IsBarSpecified = false;
this.OnMyFooBar(e);
}

//And raising the MyFooBar event is the same, other than changing to the custom EventArgs:
protected virtual void OnMyFooBar(MyCustomEventArgs e)
{
if MyFooBar != null)
MyFooBar(this, e);
}

And in your Form, you'd have this instead:

this.oMyControl.MyFooBar += new EventHandler<MyCustomEventArgs>(this.oMyControl_MyFooBarHandler);

private void oMyControl_MyFooBarHandler(object sender, MyCustomEventArgs e)
{
// whatever your code needs to be, such as
string message = "FOO was specified!";

if (e.IsBarSpecified == true)
message += " BAR too!");

MessageBox.Show(message);
}

Or this, if you want to use an anonymous delegate (note that since I'm utilizing the custom MyCustomEventArgs, I'll need to specify them here, whereas I didn't need any of the parameters in the first example):

this.oMyControl.MyFooBar += delegate(object sender, MyCustomEventArgs e)
{
// whatever your code needs to be, such as
string message = "FOO was specified!";

if (e.IsBarSpecified == true)
message += " BAR too!");

MessageBox.Show(message);
};

3 comments:

  1. Hello Bonnie,

    I thought I would mention that for .NET 2.0 it is preferred to use EventHandler<TEventArgs> over a custom delegate. Getting rid of all those delegate declarations is very handy.

    In your example, MyCustomEventHandler becomes EventHandler<MyCustomEventArgs>.

    ReplyDelete
  2. Hey tergiver,

    You're correct of course. I'll take some time in the next day or so to fix my example. Thanks for the heads-up.

    ReplyDelete
  3. Sample code has been updated! Thanks tergiver!

    ReplyDelete