Click here to Skip to main content
15,868,141 members
Articles / Programming Languages / C#

Prism Event Aggregator Service and Extension Methods

Rate me:
Please Sign up or sign in to vote.
4.50/5 (12 votes)
24 Mar 2009CPOL5 min read 104.4K   932   23   29
The extremely easy way to connect your code

Introduction

One of the most challenging issues I encounter in my development projects is connecting my code parts together. (By parts, I mean: User controls, Entities, External project resources and so forth). I was certain the answer to resolve this issue is using the .NET framework’s Events mechanism. I wanted to develop generic, loosely coupled and easy to use solution to create a strong infrastructure for all my projects.

Background

I suggest you take a look on the Prism event aggregator service and C# extension methods feature.
Here are the solutions I tried before I arrived at the ideal one (For easy discussion, I am presenting the solution with WPF user controls, but it still holds for other pieces of code):

  1. Wiring the parts with events – The event declaration is inside the user control. Say we have user controls A, B and C. I can declare an event inside C and register for it with A and B, then A and B can get notifications from C each time an event is raised.
    Very quickly, I left this solution because it's tightly coupled and may cause memory leak problems. The publisher and the subscriber have to know of each other which is a bad design, and a subscriber can't be collected by the GC if it's connected with the publisher with strong event reference unless you explicitly un-hook it which makes the solution even more tedious (we're here to save time, not make more work!).
  2. Using WPF event routing – Although WPF Event Routing is a very good feature in WPF, it is a WPF specific solution and I need a generic one. Also, one cannot use it everywhere even if the project is WPF.
  3. Using CAB event broking service – CAB event broking service lets you wire any parts of the code in a loosely coupled manner; it's very robust and seems suitable for my purpose. My problem with this easy solution is that my project has to be a CAB project. I can't use the Broking service out of CAB (at least I don't know how to), so it wasn't reusable for me.
  4. Prism aggregator service - The fourth solution I considered was the Event Aggregator Service shipped with the new WPF Prism project introduced by the P&P team from Microsoft. The cool thing with this service is that it is independent from using Prism based project so you can import its functionality as a standalone service. 

Inside the Solution

First I have to add for my project (Class library project) called GenericEventAggregator three DLLs which event service needs:

  • Microsoft.Practices.Composite
  • Microsoft.Practices.Composite.Wpf (Though it is named WPF, it does not rely on WPF and can be used in any project.)
  • Microsoft.Practices.ObjectBuilder2

Now I have to add a factory method class to help me access the aggregator in a simple way:

C#
    public static class ServicesFactory
    {
    // Singleton instance of the EventAggregator service
    private static EventAggregator eventService = null;

    // Lock (sync) object
    private static object _syncRoot = new object();

    // Factory method
    public static EventAggregator EventService
    {
        get
        {
            // Lock execution thread in case of multi-threaded
            // (concurrent) access.
            lock (_syncRoot)
            {
                if (null == eventService)
                {
                    eventSerice = new EventAggregator();
                }
                // Return singleton instance
                return eventSerice;
            } // lock
        }
    }
}        

Now I need to add a generic EventArgs class that inherits from the CompositeWpfEvent class. For each event to be published, we need to join .NET object  (event value) and a topic (event topic). This way subscribers can hold the object publishers send and use the topic to filter the events shoot by the publishers.

C#
public class GenericEvent<tvalue /> <TValue>: CompositeWpfEvent<EventParameters<TValue>>{ }
  public class EventParameters<TValue>
  {
      public string Topic { get; private set; }
      public TValue Value { get; private set; }
  }

You see a new helper class EventParameters. This class can help to envelope any object wanted to be used with the service, and a topic of the event. I derived from Glenn Block’s article about Firing generic events with EventAggregator.

As funny as it may seems, that’s it! We don't need anything else to start using the service. You can create your project, add the GenericEventAggregator project reference and start using it. I created a standalone class library project for the coming enhancements.

Now add a new WPF project (it's only an example, you can use whatever kind of project you like) called MyEventAggregatorSeriveTest.

Add to user controls SubscriberUserControl and PublisherUserControl.

Now add the event aggregator publishing event syntax in the Button event:

C#
ServicesFactory.EventService.GetEvent<GenericEvent<string><genericevent<string />>().Publish
	(new EventParameters<string /> { Topic = "PublisherUserControlEvent", 
	Value = "Hello Event Aggregator" });

This way we told the aggregator service to publish an event with topic PublisherUserControlEvent and a value Hello Event Aggregator.  We need the PublisherUserControlEvent string for filtering task, meaning if another control publishes an event with object string, then we have to filter subscribers for string object for listening to certain events based on the topic.

Now we have to add a subscriber to the event, so when user clicks the button, the subscriber control has to do something. We can do it in the SubscriberUserControl constructor:

C#
ServicesFactory.EventService.GetEvent<<genericevent<string />GenericEvent<string>>().Subscribe(
s =>
{
    if (s.Topic == "PublisherUserControlEvent")
        tblockEventValue.Text = s.Value;
}
);

Here the subscriber control registers to the events with object string but can filter this event by the event’s topic.

Run the project and test it. After pressing the button, you'll see the value in the subscriber control.

That’s pretty cool; I can communicate between the two controls without any need for both controls knowing of each other.

Now you can extend the use of the service wherever you want in your projects.

Improving the Concept

After I started using the new service, all the time I ask myself, “How I can give my project objects to use the service as a method inside of them?”.
It would be very cool if I could do the following statement:

C#
MyObject.PublishEvent(MyEventTopic) 

This statement will publish the event without any need each time to use the statement I mentioned above:

C#
ServicesFactory.EventService.GetEvent<GenericEvent<string><genericevent<string />>().Publish
    (new EventParameters< MyObject > { Topic = MyEventTopic , Value = MyObject.value});

Suddenly, I remembered the Extensions Methods feature shipped with the C# 3.5. It came to the rescue. If I write an extension method with object type parameter and implement the publish statement, then I can achieve what I want.

So, I added an ExtensionServices class to the GenericEventAggregator project:

C#
public static class ExtensionServices
    {
        //Supplying event broking mechanism to each object in the application.
public static void PublishEvent<TEventSubject>
	<teventsubject />(this TEventSubject eventArgs,string eventTopic)
       	 {            	ServicesFactory.EventService.GetEvent
					<GenericEvent<TEventSubject><genericevent<teventsubject />>()
.Publish(new EventParameters<TEventSubject><teventsubject /> { Topic= eventTopic, Value= eventArgs});
        }
    }

PublishEvent is the extension method which can be used with each object to do the service mechanism. So the PublisherUserControl publishing code will become:

C#
"Hello Event Aggregator".PublishEvent("PublisherUserControlEvent");

Oh, that pretty nice! Now I can simply publish an event with the service in a very simple manner:

C#
new Person().PublishEvent("Person Event") 
new DataTable.PublishEvent("Data table event") 
LinkObjectCollection.First().PublishEvent("LinkObjectEvent")

Conclusion

In this article, I presented the power of integrating the new Prism event aggregator service and the instance methods feature. All you need to start enjoying the service is adding the GenericEventAggregator DLL reference and immediately you'll start seeing the Publish event method appear in your entire projects object. All you have left to do is subscribe (and filter) and that's it.

I'll be very happy to get comments for improvements of the concept.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Free lancer
Israel Israel
I'm very interested on .Net related technologies (WPF,WCF,WF,Data services, Silverlight ...) and software Architecture issues.

Comments and Discussions

 
GeneralRe: Can this be done for Silverlight Pin
davido_xml1-May-09 4:07
davido_xml1-May-09 4:07 
GeneralRe: Can this be done for Silverlight Pin
Wasim Farhat1-May-09 8:37
Wasim Farhat1-May-09 8:37 
GeneralCool Stuff! Pin
Justin Helsley30-Mar-09 21:00
Justin Helsley30-Mar-09 21:00 
GeneralRe: Cool Stuff! Pin
Wasim Farhat30-Mar-09 22:06
Wasim Farhat30-Mar-09 22:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.