Introduction
An event is a mechanism via which a class can notify its clients when
something happens. For example when you click a button, a button-click-event
notification is sent to the window hosting the button. Events are declared using
delegates. So if you don't know what a delegate is, you may go and read my
article on delegates first. The first time you go through this article you might
find it confusing, don't worry about that. Just try out the sample program and
go through the sample source, line by line. Maybe, you can read the article once more
after that. Once you get the hang of it, things will seem simple. By the way
this article is intended for beginners and is not meant for advanced level
programmers.
The Program
I include the full program below. It's not commented but later down this
article, I have taken the program part by part and explained each part. I have
also included the output you'll get on running the program.
using System;
public delegate void DivBySevenHandler(object o, DivBySevenEventArgs e);
public class DivBySevenEventArgs : EventArgs
{
public readonly int TheNumber;
public DivBySevenEventArgs(int num)
{
TheNumber = num;
}
}
public class DivBySevenListener
{
public void ShowOnScreen(object o, DivBySevenEventArgs e)
{
Console.WriteLine(
"divisible by seven event raised!!! the guilty party is {0}",
e.TheNumber);
}
}
public class BusterBoy
{
public static event DivBySevenHandler EventSeven;
public static void Main()
{
DivBySevenListener dbsl = new DivBySevenListener();
EventSeven += new DivBySevenHandler(dbsl.ShowOnScreen);
GenNumbers();
}
public static void OnEventSeven(DivBySevenEventArgs e)
{
if(EventSeven!=null)
EventSeven(new object(),e);
}
public static void GenNumbers()
{
for(int i=0;i<99;i++)
{
if(i%7==0)
{
DivBySevenEventArgs e1 = new DivBySevenEventArgs(i);
OnEventSeven(e1);
}
}
}
}
//Output
F:\c#\events>1
divisible by seven event raised!!! the guilty party is 0
divisible by seven event raised!!! the guilty party is 7
divisible by seven event raised!!! the guilty party is 14
divisible by seven event raised!!! the guilty party is 21
divisible by seven event raised!!! the guilty party is 28
divisible by seven event raised!!! the guilty party is 35
divisible by seven event raised!!! the guilty party is 42
divisible by seven event raised!!! the guilty party is 49
divisible by seven event raised!!! the guilty party is 56
divisible by seven event raised!!! the guilty party is 63
divisible by seven event raised!!! the guilty party is 70
divisible by seven event raised!!! the guilty party is 77
divisible by seven event raised!!! the guilty party is 84
divisible by seven event raised!!! the guilty party is 91
divisible by seven event raised!!! the guilty party is 98
F:\c#\events>
Explanation
Okay. I presume you have taken a look at the above program and I bet you have all
guessed it's purpose. We generate some numbers and every time we generate a
number that is divisible by 7 we raise an event. The event handler will print
out a message saying that the event was raised and it also prints out the number
responsible for raising the event. I guess some of you are frowning and saying
that's a stupid reason to raise an event. I know, I know alright. The program is
not intended to be used for any useful purpose. It's only an attempt to make
events comprehensible. I hope it served it's role out. :-)
Okay, so the first thing we did was to declare a delegate.
public delegate void DivBySevenHandler(object o, DivBySevenEventArgs e);
The delegate defines the parameters sent to the event handlers. Thus any
class that wants to handle this event must have a handler method which has the
same return type and argument list as this delegate. Here as you can see, the
first parameter is an object. In real-world cases event handlers are normally
passed a reference to the sending object. I am not doing that in this program. I
am simply passing a new object()
to the event handler. Normally you
can pass a this
reference. The second parameter is a System.EventArgs
derived class. System.EventArgs
is the base class for encapsulating event related data.
We use it to send information regarding the event to its handler.
Now, we define the EventArgs
derived class as follows:-
public class DivBySevenEventArgs : EventArgs
{
public readonly int TheNumber;
public DivBySevenEventArgs(int num)
{
TheNumber = num;
}
}
As you can see, it has a public read-only member which is used to store our
generated number that is divisible by 7. Normally you should use properties but
for the sake of simplicity I am using a public member variable.
Now we define our listener class which is the class that needs to be notified
of the event.
public class DivBySevenListener
{
public void ShowOnScreen(object o, DivBySevenEventArgs e)
{
Console.WriteLine(
"divisible by seven event raised!!! the guilty party is {0}",
e.TheNumber);
}
}
As you can see, it has a function ShowOnScreen
that matches the delegate type
we defined on top. You can see how we use the passed DivBySevenEventArgs
object
to print out the number that is divisible by seven.
Now, let's examine our Main()
containing class. We first declare the event as
follows:-
public static event DivBySevenHandler EventSeven;
An event is declared like a delegate type variable, except that the keyword event
precedes the event declaration.
Now let's take a look at the function that invokes the event and thus
notifies all clients.
public static void OnEventSeven(DivBySevenEventArgs e)
{
if(EventSeven!=null)
EventSeven(new object(),e);
}
EventSeven
will be null
if no client has hooked up a delegate to the event.
We need to check if it is null
unless you want to see an exception raised. If
it's not null
we invoke the event, passing a dummy object [I have explained
above why I passed a dummy] and the passed DivBySevenEventArgs
object. And all
clients get notified.
Let's look at the function GenNumbers()
now :-
public static void GenNumbers()
{
for (int i=0;i<99;i++)
{
if(i%7==0)
{
DivBySevenEventArgs e1 = new DivBySevenEventArgs(i);
OnEventSeven(e1);
}
}
}
We use the for()
loop to iterate from 0 to 98, and in each case we check for
divisibility by 7. If we find that the number is divisible by 7 we create a
DivBySevenEventArgs
object passing the culprit number to the constructor. Now we
call the OnEventSeven()
function passing the DivBySevenEventArgs
object we just
created.
Now lets go through Main()
public static void Main()
{
DivBySevenListener dbsl = new DivBySevenListener();
EventSeven += new DivBySevenHandler(dbsl.ShowOnScreen);
GenNumbers();
}
We first create a DivBySevenListener
object. Then using the +=
operator we compose a delegate into the event field. Even though I haven't used
the -=
operator, you can use it to remove a delegate from
an event. Once we've done all that we call GenNumbers()
. Thus we've set
everything up nice and proper. GenNumbers()
will do its job like a faithful
puppy by generating numbers from 0 to 98 just as we expected it to. Every time
it generates a number divisible by 7 it will raise the event.
Conclusion
Well you have just seen how you can create events and event handlers. You
must remember that events can be invoked only from the class that declared them.
This causes problems with regard to inheritance. Thus if you have a class with
an event you'd better make your OnWhateverEvent() function protected so that the
derived classed can call it. Better still, make it virtual too, so they can
override it in their class.