C# Events

What is an Event?
Each of these is similar because it allows a direct command to be given to a class or object within the flow of a program. This is similar to the early programming languages, which simply processed a sequence of commands and loops until complete.

The sequential or procedural method of programming is limited to this type of processing. However, C#’s object-oriented approach is also event-driven. This means that as activities occur, a class may raise events to indicate the action that happened and to pass related information to other classes that have subscribed to the event. These may be used for various purposes including indicating the progress of a long-running process.

A key advantage of using events is that a class that publishes an event does not need to know the details of the subscribers at design-time. As events are based upon delegates, the subscribers are only added when the program is running.

Creating an Event
There are three parts to creating an event handler within a class. Firstly a delegate is required. The delegate is used to hold the details of the subscribers to the event. Secondly, a public event is created. This event is visible externally to the class and used for creating the event subscriptions. It is also the member that is visible using Visual Studio’s Intellisense feature. Finally, a method is created within the class. The method contains the code that fires the event. Each of these three elements is described in the following sections.

To provide an example of the use of events, we will create a new program containing a class that represents a car. When the car’s speed exceeds a safety limit, an event will be fired. To begin, create a new console application named “EventDemo”. Add a class file named “Car” to the project and add the following code to the class to create a read-only Speed property and an Accelerate method. The _safetySpeed variable holds the maximum speed permitted and will be used later.

Creating the Delegate
The delegate for an event is declared using the standard syntax for any delegate. However, it should be declared with a data type of void as events are multicasting. This means that multiple subscribers can be attached to a single event with each being notified of the event in turn.

The delegate’s signature is important as this is the signature that subscribers will see. To comply with the expected standards, the signature should contain two parameters. The first parameter should be an object named ‘source’. This will contain a reference to the object that raised an event. The second parameter should be of the type EventArgs and should be named ‘e’. EventArgs is a special class that can be derived from to create custom classes for passing information when an event fires. This is described later in this article.

In this example we will add an event to the Car class that is raised when the car exceeds the safety limit speed. To create the delegate for this event, add the following code to the namespace (outside of the class definition).

public delegate void SpeedLimitExceededEventHandler(object source, EventArgs e);

Declaring the Event
The event is the publicly visible element of the class. It can be subscribed to by other classes that wish to react to the event being fired. The event is declared by prefixing its name with the event keyword and the name of the delegate that the event will be based upon. To create the event for the Car class, add the following to the class:

public event SpeedLimitExceededEventHandler SpeedLimitExceeded;

Creating an Event Method
An event method is a single method used to raise an event. Although it is not strictly necessary to create such a method, it is advantageous as it makes maintenance of the code simpler and allows derived classes to override the functionality and alter the manner in which events are fired.

To create the event method for the SpeedLimitExceeded event, add the following code to the Car class.

There are several items to note in this method. Firstly, the method is marked as virtual. This keyword will be described in detail later in the tutorial. It means that the functionality of this method may be overridden and changed by classes that are derived from the Car class.

The method is named using the name of the event and the prefix ‘On’. This is a simple convention that developers expect to see. The event method requires only a single parameter containing the event arguments for the raised event. This parameter holds all of the information that is to be passed to the event subscribers.

Within the method’s code block, an if statement checks to see if the event is set to null. This conditional statement checks that there is at least one subscriber to the event as if there are no subscribers, firing the event would cause an exception to be thrown. If the test is passed, the event is raised as if it where a method, passing a reference to the current object and the event arguments that were passed in the parameter.

Calling the Event Method
To complete the sample Car class, the event method needs to be called when the car accelerates past the safety speed. Amend the Accelerate method as follows so that the event is raised when the car’s speed changes from below or equal to the safety speed to above it.

Subscribing to an Event
To subscribe to an event, a reference to a method must be added to the event. This is achieved in a similar manner to adding references to a multicast delegate. Each method that is to be called when the event is raised is added to the event using the addition compound assignment operator (+=). The signature of the added methods must match that of the delegate that the event is based upon.

Adding the CarSpeedLimitExceeded Method
In the car example, we will add a new method that captures the event that occurs when a car exceeds the safety speed. This method, named CarSpeedLimitExceeded, is added to the Program class of the console application. It will extract the speed from the source object and output a warning message. The two parameters of the method match the event delegate and will receive the Car object raising the event and the associated event arguments. Add the following method to the Program class:

Subscribing to the SpeedLimitExceeded Event
Now that the event has been created and a method exists that will react to the event, we will create a Car object and subscribe to its event. Add the following code to the Main method of the program:

The first line of code above creates a new Car object. The second line using the compound assignment notation to link the CarSpeedExceeded method to the SpeedLimitExceeded event of the object. Now when the event is fired, the linked method will be executed.

To test the event, modify the Main method as follows and execute the program:

/* OUTPUT
Speed: 30mph
Speed: 60mph
Speed limit exceeded (90mph)
Speed: 90mph
*/

Removing Event Subscriptions
As with delegates it is important to release event references when they are no longer required. To end a subscription use the subtraction compound operator (-=). For example, to unsubscribe and release the CarSpeedLimitExceeded reference, you can use the following code:

Event Arguments
Earlier in this article I mentioned the use of event arguments. These contain additional information that is passed when an event is raised. So far, we have been using a basic EventArgs object to represent these event arguments. The EventArgs class contains no properties that make it useful in itself. To provide the additional information we need to create a new class derived from EventArgs with the additional properties that we wish to pass.

Creating a Custom EventArgs Class
New classes for passing event arguments should inherit from EventArgs. Inheritance is beyond the scope of this article and will be explained later in the tutorial. However, to show the use of event arguments we will create such a class for the speeding car example.

To begin, create a new class file containing a class named SpeedEventArgs. To indicate that the class is derived from EventArgs, the base class name is added after the new class’ name with the two separated by a colon (:). The new class requires a single property that holds the excess speed for cars travelling faster than their safe speed. The final code for the class is therefore:

To use the event arguments with our existing event, several modifications need to be made. Firstly, the delegate for the event must be updated to replace EventArgs with SpeedEventArgs as follows:

The OnSpeedLimitExceeded method’s signature needs to be updated to use the new type:

Next the call to the OnSpeedLimitExceeded needs to be modified. The Accelerate method will now calculate the difference between the car’s current speed and the safety speed. This will be assigned to the event argument property so that it can be passed to subscribing methods. The updated Accelerate method is as follows:

Finally, the subscribing method’s signature within the Program class must be updated to accept the new event arguments and react accordingly:

These changes mean that the excess speed is now reported by the event itself. As there is no requirement for the program to know what the car’s safety limit is, this provides a good example of encapsulation. Execute the program to see the new results.

Tagged , . Bookmark the permalink.

2 Responses to C# Events

  1. Nirav Patel says:

    Declare delegate with public prefix ..else user will get error..
    ex:
    public delegate void SpeedLimitExceededEventHandler(object source, EventArgs e);

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.