Handling Events In C#

 

Events provide a very powerful (andconvenient) means for interprocess communication. They are particularlyuseful when changes in the operating environment require immediateresponse from concerned software modules. When we click on a button ina dialog box, for instance, an event is generated that tells theunderlying program to take appropriate action. However, it is notnecessary that an event be raised only in the case of an externalaction like a mouse click. Events can also be raised as a result ofinternal operations.

One of the greatest advantages ofcommunication through events is that the sender and the receiver(s) ofthe messages (events) are loosely coupled. That is to say, asender-receiver relationship is not static and such relationships canbe established dynamically. When we write software using modernlanguages , we need to use events extensively to establishcommunication links between different modules. This article provides anintroduction to how to do this in the context of C#.

The mechanism for implementing event-basedcommunication is very similar to the way we go about enlistingourselves for receiving information from various sources in everydaylife. As an example of such an activity, let us consider the process ofsubscribing to a magazine. The two entities absolutely essential forthis are a publisher of a magazine and a subscriber. Similarly, forevents, we need to have a sender of the event and a receiver orlistener.

In order to subscribe we must enlist ouselvesas subscribers and provide an address in a predefined format so that wemay receive the magazine at that address. The publisher maintains alist of subscribers and, when the magazine is ready, a copy is sent toeach name on that list.

The sender of an event, too, maintains such alist and also specifies a format for enlisting an \"address\". Thisformat is implemented through a delegate. A delegate is a template fora method that every subscribing class must implement in order to beincluded in the sender's list. So the first step in implementing eventsis to declare a delegate as follows :

public delegate void EventNameEventHandler( object sender, EventNameEventArgs e);

where 'EventName' is the name of the event to be raised and the second argument (<eventname>EventArgse) specifies a class that encapsulates information about the event. Inour example of subscription, it correponds to the magazine. This class,which must derive from System.EventArgs, is created as follows :</eventname>

public class EventNameEventArgs : EventArgs
{



}

The <eventname>EventArgs class will includeone or more properties which the client (subscribing) classes can readto get the necessary information about the event. The two elementsdescribed so far are independent entities and are not to be incuded inthe class that is raising the event.</eventname>

Many delegates and corresponding 'EventArgs'classes are already available in the .NET Framework class librarycovering standard events like mouse or key actions. If one of these canbe used by you then it is not necessary to define the two aboveelements. The procedure described here is the general one forimplementing event functionality and will come in handy when you needto create your own special events.

The next step is to create the class thatraises the event — in our example the publisher of the magazine. Thisclass must incorporate two elements : an event and a method fornotifying all subscribers. The first is used to hold the names of theclient (subscriber) classes. The second element is like the mailingdepartment of the publisher — it sends the description of the event (<eventname>EventArgs) to all registered subscribers. The event is declared as follows :</eventname>

public event EventNameEventHandler EventName;

Note that we only declare the event and do not create it. The method for notifying all registered clients is written thus :

protected virtual void on EventName(EventNameEventArgs e)
{



}

And now let's look at what the subscriberneeds to do in order to receive her magazine. First she has to registerher name in the mailing list and, second, she has to have a mailboxbearing her address in the same format as specified by the publisher.Here our client method takes the first step using the followingstatement :

sender.EventName += new EventNameEventHandler(MyHandler);

where 'sender' is the reference to the objectthat is going to raise the event (EventName) that the client isinterested in and 'MyHandler' is the method that handles the event inthe client class. Referring to our example, this registers thereceiving address (MyHandler) with the mailing list — the eventdeclared in the sending class. It is possible to deregister too likethis :

sender.EventName -= new EventNameEventHandler(MyHandler);

And finally the method to handle the event has to be written like this :

public void MyHandler(object sender, EventNameEventArgs e)
{



}

The signature of this method has to beidentical to that of the delegate declared earlier. In other words, theaddress format specified by the publisher has to be adhered to.

To summarise :

Step 1 : Declare a delegate.
Step 2 : Create a class derived from System.EventArgs to encapsulate the event information.
Step 3 : Create the class that will raise the event. This class will have :
a) an event which will have the registered clients
b) a method to notify registered clients.
Step4 : Create a client class. This class will have a method that matchesthe signature of the delegate. This method will receive the event.
Step 5 : Register this method with the event as being the authorized listener for the event.

The mechanism for handling events is nowcomplete. The example given below has an 'EvenDetector' class thatgenerates random numbers and when two successive numbers happen to beeven, it generates an 'Even' event. The 'EvenListener' class receivesthe event and announces it to the whole wide world (yet another 'www'!)by printing a message on the screen.

//Start of program
using System;
using System.ComponentModel;

// First step — declare the delegate
public delegate void EvenEventHandler(object sender, EvenEventArgs e);

//Second step — create a class derived from EventArgs
public class EvenEventArgs : EventArgs
{
// Declare private variables to reflect the information
// about the event
private readonly bool evensteven;
private readonly int evenone, eventwo;

//Constructor
public EvenEventArgs(bool evensteven, int evenone, int eventwo)
{
this.evensteven = evensteven;
this.evenone = evenone;
this.eventwo = eventwo;
}

//The properties to enable the client to access the event info
public bool Evensteven
{
get
{
return evensteven;
}
}
r /> public int Evenone
{
get
{
return evenone;
}
}

public int Eventwo
{
get
{
return eventwo;
}
}
}

//Third step — create the class that will raise the event
public class EvenDetector
{
//Declare some variables to make life simpler
private bool goteven, done;
//and our own random number generator
private Random r1;
//as well as the number we shall check for 'evenness'
private int randomnum;
//Also the two even numbers
private int evenone, eventwo;

//Constructor
public EvenDetector()
{
r1 = new Random();
}

public void numbercruncher()
{
//Loop until two successive even numbers have been generated
while(!done)
{
randomnum = (int)(100*r1.NextDouble());

if(randomnum%2==0)
{
if(goteven)
{
done =true;
eventwo = randomnum;
}
else
{
goteven = true;
evenone = randomnum;
}
}
else
{
goteven = false;
}
}

//Success — create an object for the client(s)
EvenEventArgs e = new EvenEventArgs(done, evenone, eventwo);

//and call the method to send it to the client(s)
OnEven(e);
}

//Step 3a — the event is declared
public event EvenEventHandler Even;

//Step 3b — the method that notifies client(s)
protected virtual void OnEven(EvenEventArgs e)
{
// If the list of clients is NOT empty
if(Even != null)
{
//despatch the event to each client
Even(this, e);
}
}

}

//Fourth step — and now the client class
public class EvenListener
{
//This is the method with the same signature as
//the delegate. It will receive the event
public void EvenAnnouncer(object sender, EvenEventArgs e)
{
//This will always be true and hence is redundant.
//Just illustrates the use of EventArgs
if(e.Evensteven)
{
Console.WriteLine("THE EVEN TWINS ARE HERE! — {0} and {1}", e.Evenone, e.Eventwo);
}
}
}

//Fifth step — hook 'em up
public class EvenTester
{
public static void Main()
{
//Instantiate EvenDetector
EvenDetector ed = new EvenDetector();

//Instantiate EvenListener
EvenListener el = new EvenListener();

//Register the listener method
ed.Even += new EvenEventHandler(el.EvenAnnouncer);

ed.numbercruncher();
}
}

//End of program

You can copy the code and save it as'EvenDetector.cs'. To compile the code type 'csc EvenDetector.cs' atthe command line and the program can be run from the command line bytyping 'EvenDetector'.

I hope you find this interesting and useful.If you would like to study this subject further, the best source torefer to is the .NET Framework SDK Documentation.

Happy Programming!

Related Articles :

Twitter Digg Delicious Stumbleupon Technorati Facebook Email

No comments yet... Be the first to leave a reply!