Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

EventAggregator - My Take

5.00/5 (5 votes)
21 Jan 2024CPOL2 min read 5.7K   92  
A dead simple message passing framework
The EventAggregator framework enables communication between loosely coupled components using an event mechanism. This article will discuss the inner workings of this simple implementation of the EventAggregator.

Introduction

The EventAggregator framework enables communication between loosely coupled components using an event mechanism. This article will discuss the inner workings of this simple implementation of the EventAggregator.

In the past, I've used the EventAggregator implementation provided by Prism, but unlike the Prism implementation, this version has less of a footprint and is Open Source.

At this point, I should admit that I got the basic code from ChatGPT, but it was buggy and lacked genericity (new word, maybe it will catch on). So with a bit of Googling and a little common sense, I adapted the code to suit my needs and maybe yours.

An EventAggregator broker reference needs to be placed in a global area that is accessible to all that are needing to use the EventAggregator framework. In my C# WinForms application, I placed the broker in Program.cs.

C#
public static EventAggregator<IEventArgs<Object>> g_aggregator = 
    new EventAggregator<IEventArgs<Object>>();    

The heart of this EventAggregator implementation is the EventAggregator class. It provides the Publish and Subscribe methods that take a generic event type, based on the IEventArgs interface and stores the Event type and a list of delegates in a generic Dictionary data structure.

The Subscribe method first extracts the eventType from the Action TEvent then checks whether the eventType has an entry in the Dictionary; if it does not, then a new entry is created and if it does already contain an entry, the delegate is added to the List of delegates.

In the Publish method; the eventType is extracted and if there is an entry in the Dictionary, then the delegates in the delegate list are invoked. If there are no entries, nothing is done and the method just returns to the caller.

C#
public class EventAggregator<T>
{
private readonly Dictionary<Type, List<Delegate>> subscribers = 
                            new Dictionary<Type, List<Delegate>>();

// Subscribe method to register an event handler
public void Subscribe<TEvent>(Action<TEvent> handler)
{
    Type eventType = typeof(TEvent);

    if (!subscribers.TryGetValue(eventType, out var handlers))
    {
        handlers = new List<Delegate*gt;();
        subscribers[eventType] = handlers;
    }

    handlers.Add(handler);
}

// Publish method to raise an event and notify subscribers
public void Publish<TEvent>(TEvent message)
{
    Type eventType = typeof(TEvent);

    if (subscribers.TryGetValue(eventType, out var handlers))
    {
        foreach (Action<TEvent> handler in handlers)
        {
            handler.Invoke(message);
        }
    }
}   

I chose a very generic test case for evaluating the usefulness of the EventAggregator. It utilizes a TestMessage based on the IEventArgs interface and includes a reference to the Test class.

C#
public interface IEventArgs<T>
{
    T GetData();
}

public class TestMessage : IEventArgs<Test>
{
    Test test { get; }

    public TestMessage(string s, int i)
    {
        test = new Test(i, s);
    }

    public Test GetData()
    {
        return test;
    }
}

public class Test
{
    public int IntProp { get; set; }
    public string StrProp { get; set; }

    public Test(int i, string s)
    {
        IntProp = i;
        StrProp = s;
    }

    public override string ToString()
    {
        return StrProp + " - " + IntProp.ToString();
    }
}  

To Subscribe to the TestMessage type message, you need only to call the Subscribe method and provide the type of message you want to receive and a handler to process the message.

C#
Program.g_aggregator.Subscribe<TestMessage>(HandleTestMessage);

private void HandleTestMessage(TestMessage message)
{
    MessageBox.Show($"Received message: {message.GetData().ToString()}");
}   

To Publish a message is just as simple, just provide a message of the type you wish to send and post it to the EventAggregator's Publish method.

C#
Program.g_aggregator.Publish(new TestMessage("TestMessage - ", 42));

Although the implementation of the EventAggregator is a very simple example of a messaging framework, it has a lot of flexibility. I chose this implementation over other frameworks of this kind because this implementation is a lot simpler and has less of a footprint.

History

  • 21st January, 2024: Initial version

License

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