Introduction to Events in the CAB (Introduction to CAB/SCSF Part 11)

Introduction

Part 10 of this series of articles
described how the CAB implements commands. The CAB also provides a new way of raising and sinking events. This article will describe how this works.

Overview of events in .NET

Events in .NET are a publish-subscribe mechanism. We declare an event in a publisher class, instantiate the class, and then other objects can subscribe to the event. When they subscribe these objects identify a method that will be called when the event is fired.

We can then ‘publish’ by firing the event from the original publisher object. The methods on the subscriber objects are called.

This is an implementation of the Observer design pattern, and gives the benefits and liabilities of that pattern as outlined in the book ‘Design Patterns’ by Gamma, Helm, Johnson and Vlissides. In particular it allows for loose coupling between classes. Events are a callback mechanism, allowing code to be called without the caller necessarily having any direct reference to the object being called.

This mechanism is used throughout the .NET framework, particularly for such things as handling events raised by user interface components (e.g. button clicks).

This article assumes you know and understand all this.

Why do we need a new way of handling events?

Events in .NET are based on delegates and are extremely powerful. In many ways they are a key advantage of the language. For instance Java, which doesn’t have delegates, has some pretty nasty syntax for dealing with GUI events, and has no standard way of setting up the Observer pattern in more general cases.

So if events in .NET are so good, why have we got a new way of dealing with them in the CAB? What’s wrong with the usual events in .NET?

Problems with Events in .NET (1): Syntax

One problem with the current .NET eventing mechanism is that the syntax isn’t all that transparent. This is particularly true in C# (Visual Basic has neater syntax). You have to declare a delegate, declare an event based on that delegate in your publisher class, hook subscriber methods up to the event by creating an instance of the delegate and using the ‘+=’ syntax, and then fire the event with the Invoke method. The event can only be fired directly from your publisher class, so often we’ll additionally expose a method on the publisher class to allow other objects to fire the event (this is customarily called something like ‘OnMyEvent’).

Actually things have got a little simpler than that in .NET 2.0: now there are some syntactic shortcuts (we don’t need to create an instance of the delegate directly to add our event handler to the event, for instance). But to be able to use events effectively you really need to understand the previous paragraph, which clearly isn’t straightforward.

Problems with Events in .NET (2): Hooking Up Publishers and Subscribers

Another problem with events in .NET is that it isn’t always easy to structure your code well. The aim is to have a publisher object and a subscriber object linked by an event, but without necessarily having a direct reference to each other.

To set up the event code somewhere has to be able to add the method in the subscriber object to the event in the publisher object (with the ‘+=’ syntax). This code clearly has to have a reference to both objects. This can be tricky to do in a clean way in a highly object-oriented system.

For example, I’ve seen systems where we construct a switchboard object. This is a global singleton that caches references to all of our publisher objects. The switchboard object exposes methods that allow our subscribers to subscribe to our publishers’ events, and other methods to allow the events to be raised. It can also ensure that the publisher objects can be cleanly disposed of. This works, but can get messy as the temptation is to put all publishers into the switchboard, even if they are completely unrelated.

An alternative is to create all our publishers and subscribers at start up, and to hook up the events in the start up code. This is a more standard approach, and is also in many ways the approach used by the .NET framework when it auto-generates code to hook up user interface events. However, it isn’t always practical to do it in this way.

Events in the CAB

The CAB gives us the ability to handle events in a much cleaner way. Our WorkItem containers give us a way of handling scope issues for objects, and this enables us to hook up events with a more straightforward syntax than the usual .NET syntax.

Basic Example

Yet again the easiest way to understand what we can do with CAB events is to look at a simple example.

Events can be confusing, but if you think about the basics they are actually quite simple. We want to identify some code in one or more objects (our subscribers) that will get called when another object (the publisher) says so. The difficulty is that we don’t want the publisher to have to call the subscribers directly itself: this is a callback mechanism, and we want loose coupling between our objects. We just want the publisher to be able to say ‘fire my event’.

To do this in the CAB we first give our event a string name. We then identify all the code that will get executed when the event fires by applying an attribute with this name as a parameter, as below:

        [EventSubscription("MyEvent")]
        public void MyEventHandler(object sender, EventArgs e)
        {
            MessageBox.Show("Hello from the CAB event handler");
        }

Note that the method has to be public, and to have a method signature as shown. Of course this is the usual method signature for events in .NET, although usually event handlers don’t have to be public.

This is all the set up we need to do. We can now fire the event whenever we want, again using the string name to identify it:

workItem.EventTopics["MyEvent"].Fire(this, EventArgs.Empty, null, PublicationScope.Global);

That’s all there is to it. When this code is executed the event will fire and all methods decorated with the EventSubscription(“MyEvent”) attribute will get executed. We don’t have to create delegates and events specifically, or hook anything up with the ‘+=’ syntax. It’s also much clearer what’s happening.

Note that the containing classes for both the pieces of code above must be in the Items collection of a CAB WorkItem for this to work (although not necessarily the same WorkItem, as we shall see in part 11). Also, as shown, you need to have access to the WorkItem itself to fire the event, which you can obtain by dependency injection. If you’ve been reading this series of articles you should be used to that by now.

Sample Code

Code demonstrating this is available. This has an event example with separate Publisher and Subscriber classes. However the CAB events really don’t need a specific Publisher class: you can just fire the event with the syntax shown when you need it. A second example in the same code demonstrates this. The sample code also shows that you can easily have multiple publishers of and multiple subscribers to the same event by just duplicating the syntax above.

Conclusion

This article has provided a basic introduction to events in the CAB. Part 12 of this series of articles will examine these events in some more details.

5 thoughts on “Introduction to Events in the CAB (Introduction to CAB/SCSF Part 11)

  1. Nicely explained. I tried this in my SCSF project. I published a event from the presenter and subscribed in the controller class to invoke the service. But when I publised a event in my service class, the event object is null, and hence no handlers get executed. Any ideas what I could be missing here.

Leave a comment