Introduction

There are a number of articles available which deal with delegates. The objective of this article is to present events and delegates in a very straightforward fashion, which will enable and encourage developers to include events in classes that they design and develop, as well as properties (attributes), and methods (operations).

Understanding events

To help understand events, consider the System.Web.UI.WebControls.DropDownList control that is commonly used in ASP.NET web applications. If you drop a DropDownList control called cboDropDownList on an ASP.NET Web Form, then switch to the code view, and type the object name followed by a ., the .NET IDE intellisense will display the available properties, methods, and events.

If our web page wants to subscribe to, and respond to the SelectIndexChanged event, the .NET IDE can be used to select the event, and generate the necessary definitions. Simply press tab to select the event, then type +=, and the IDE will prompt us to press tab to insert an event handler, and tab again to generate a function to receive the event.

When the application runs, if the user selects a new option from the drop down list, the method cboDropDown_SelectedIndexChanged will be called. If the contents of a second drop down list need to change in response to the item currently selected in the first one, then we have the ideal place to insert the code. Using intellisense to explore the exposed interfaces of the various classes that are part of the .NET Framework soon reveals that Microsoft implements events in their objects frequently. However, many developers overlook introducing events into their objects, thereby reducing the usefulness of the classes that they design and build.

How to build events into classes

Let us consider an object that is being constructed using C# to implement the business rules behind creation of invoices:

We are going to suppose that the client application can contain multiple views of the invoice, and that should the invoice be changed in any way, then all of the views would like to be informed such that they can independently update their user interfaces.

The set of steps involved in creating an event to enable this functionality for clients of objects constructed using this class is detailed below:

1. Create a sub-class of the EventArgs class

When we constructed the event handler associated with the DropDownList, it contained two parameters - a sender object, and an EventArgs object:

When constructing our own class that can raise events, we can have whatever parameters we like, but we will opt to stick to the standards that the Microsoft .NET Framework objects adhere to.

The first parameter - object sender – is always the source object that generated the event. In the example above, sender would contain cboDropDown cast into an object (the implementation in the event handler can easily cast it back to a DropDownList).

The second parameter - EventArgs e – contains very little information which is of any use for a DropDownList. The Invoice class is going to pass a more useful set of event arguments as follows:

Now when an event handler is being called because a property within the object of class Invoice is called, it will include a BusinessObjectEventArgs object. This set of event arguments will be very useful, and will contain more information than can be obtained by having access to the Invoice object itself namely – the name of the property which has changed, its new value, and the value it contained immediately before it changed.

2. Create the delegate

The next step is to create the all-important delegate. Consider the following delegate:

A delegate may be thought of as the blue-print, or interface for a call-back function. When an event in the Invoice class fires, it is going to call an event handler. That event handler is going to be of type BusinessObjectEventHandler i.e. it will contain two parameters, a sender and a BusinessObjectEventArgs object.

Understanding delegates really does come down to that simple definition. A delegate is the interface definition of a call-back function.

3. Create the event

Once an EventArgs sub-class has been designed, and implemented, and the delegate (interface definition for the call-back function) has been declared, the next step is to define an event within the Invoice class as follows:

publicevent BusinessObjectEventHandler OnChanged;

The Invoice class now contains an event called OnChanged, the event handler for which is of type BusinessObjectEventHandler.

4. Raise the event

When the client application uses the Invoice class, they may subscribe to the OnChanged event, using the approach taken in the Understanding Events section.

The last thing left to do in the Invoice class is to cause the event to be raised to any client application that has subscribed to the event. This is achieved by modifying the two property set functions as follows:

Conclusion

The original premise was that an application envisaged having multiple views of the same Invoice business object. When any one of the views updated that business object, all the other views need to be notified such that they can update their user interface (this is a common application problem, think Windows Explorer, or the Visual SourceSafe user interface etc.).

With the following four simple steps:

Create a sub-class of the EventArgs class.

Create the delegate (interface definition for a call-back function).

Create the event.

Raise the event.

The Invoice class has been enhanced with events to meet the original requirement.

A footnote on designing for events

Events should be an intrinsic part of any class design. An object oriented designer / developer will automatically ask "What properties should my class expose?" and "What methods should my class support?". They will seldom think, "What events should my class raise?" Adding support for events in C# classes is very straightforward, and enhances those classes by adding powerful functionality that cannot be added in any other way. Even if there is no immediate need for events within a class, designers and developers should think about it in future. Often, objects go into production, and end up being consumed by client applications unforeseen in the original design. Even if there is no immediate need for events, if they exist, they will almost certainly be utilized at some time or the other, as the class is instantiated, and used. Design useful events into classes today and avoid having to re-code those classes tomorrow. However, not only are delegates (and therefore events) often over-looked in C# development, but the UML 2.0 standard for class diagrams does not include anywhere to design events into a class (at least not that I have found). If there is no way for a class designer to indicate that they would like events to be built into a class, how are they ever going to get developed?

My recommendation is to use the «event» stereotype when developing UML class diagrams to indicate the design for the event as follows:

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Share

About the Author

Graham works as a senior developer / software architect for WebSoft Consultants Limited, devloping using a number of software technologies, concentrating on the C# / .NET technology set.

Areas of expertise include document management, n-tier enterprise business systems, and exploitation of workflow technology, as well as a wide range of development methodologies including agile model driven development, and UML.

Way too late to the party but anyways, here it is for the posterity:
You can't do boolean checks on an event, an event is just a way to encapsulate a private reference to the delegate and to provide a way to add or remove method pointers in the invocation list held by the delegate. With events you can't get or set the a value, just to subscribe or unsubcribe handlers for the event.

I do not know how, but I used to have some understanding problems with Events and Delegates. Because your article is the clearest I have read, I improved my general comprehension of C# and .Net platform .