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.
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.
public class EventAggregator<T>
{
private readonly Dictionary<Type, List<Delegate>> subscribers =
new Dictionary<Type, List<Delegate>>();
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);
}
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.
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.
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.
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