Messaging and EventAggregator
In MVVM, ViewModels frequently need to communicate with each other without knowing about one another directly — for example, a CartViewModel adding an item should notify a HeaderViewModel to update a badge count, even though the two live in entirely different views. Direct references between ViewModels would create tight coupling and make navigation and disposal fragile. The messaging pattern (also called Pub/Sub or an EventAggregator, implemented by MVVM Light's Messenger, Prism's IEventAggregator, or CommunityToolkit.Mvvm's WeakReferenceMessenger) solves this: a publisher sends a typed message onto a shared bus, and any subscriber that registered interest in that message type receives it, with publisher and subscriber never holding a direct reference to each other.
Cricket analogy: It's like a stadium's PA announcer broadcasting 'DRS review requested' over the loudspeaker — the third umpire, the scoreboard operator, and the crowd all react independently to that one announcement without the announcer needing to personally contact each of them.
Defining and Publishing Messages
A message is typically a small, immutable class or record carrying only the data relevant to the event, such as 'CartItemAddedMessage' holding a ProductId and Quantity. The publishing ViewModel calls something like 'Messenger.Send(new CartItemAddedMessage(productId, qty))' after the state change it wants to announce, and the messaging infrastructure fans that instance out to every currently registered subscriber synchronously (or asynchronously, depending on the implementation). Because the message type itself is the contract, publisher and subscriber can be developed, tested, and even deployed as separate modules that only need to agree on the shape of the message class, not on each other's existence.
Cricket analogy: It's like a scorer logging a specific event type — 'wicket: bowled, batsman: Kohli, over: 34.2' — as a structured record that the broadcaster's graphics, the stats database, and the stadium screen all consume identically because they all understand that record's shape.
// Message definition (CommunityToolkit.Mvvm style)
public sealed class CartItemAddedMessage : ValueChangedMessage<int>
{
public CartItemAddedMessage(int newItemCount) : base(newItemCount) { }
}
// Publisher: CartViewModel
public partial class CartViewModel : ObservableObject
{
public void AddItem(Product product)
{
_items.Add(product);
WeakReferenceMessenger.Default.Send(new CartItemAddedMessage(_items.Count));
}
}
// Subscriber: HeaderViewModel
public partial class HeaderViewModel : ObservableObject, IRecipient<CartItemAddedMessage>
{
public HeaderViewModel()
{
WeakReferenceMessenger.Default.Register<CartItemAddedMessage>(this);
}
public void Receive(CartItemAddedMessage message)
{
CartBadgeCount = message.Value;
}
}Weak References and Avoiding Memory Leaks
A naive EventAggregator that holds strong references to subscribers will keep them alive forever, because the aggregator itself is typically a long-lived Singleton — a ViewModel that registers and is later navigated away from can never be garbage collected, causing a slow memory leak across navigation. This is why production messengers like WeakReferenceMessenger store subscribers via weak references (or require explicit Unregister calls in a ViewModel's Cleanup/Dispose method): the messenger's internal table doesn't itself keep the subscriber alive, so once the View and ViewModel are no longer referenced elsewhere, the garbage collector can reclaim them even if Unregister was forgotten. Best practice is still to explicitly unregister in a Dispose or OnNavigatedFrom hook, treating weak references as a safety net rather than a substitute for disciplined cleanup.
Cricket analogy: It's like a franchise keeping an injured player's name permanently on the central contract list instead of releasing them at season's end — the salary cap (memory) stays consumed by a player who will never take the field again.
Never rely solely on weak references as a substitute for explicit cleanup. If a ViewModel subscribes in its constructor, it should unregister in a corresponding Dispose(), OnNavigatedFrom(), or Cleanup() method — weak references only prevent leaks when cleanup is forgotten, they don't guarantee timely unsubscription, and a subscriber can still receive stale messages in the gap before it's collected.
- Messaging/EventAggregator lets ViewModels communicate without holding direct references to each other.
- A message is a small, typed, immutable payload; publisher and subscriber only need to agree on its shape.
- Prism's IEventAggregator, MVVM Light's Messenger, and CommunityToolkit.Mvvm's WeakReferenceMessenger are common implementations.
- Strong-reference messengers can leak memory by keeping navigated-away ViewModels alive indefinitely.
- WeakReferenceMessenger mitigates leaks by not itself keeping subscribers alive, but explicit unregistration is still best practice.
- Always unregister in Dispose/Cleanup/OnNavigatedFrom rather than relying on weak references as the only safeguard.
Practice what you learned
1. What is the primary purpose of the EventAggregator/messaging pattern in MVVM?
2. Why can a naive strong-reference EventAggregator cause memory leaks?
3. What does CommunityToolkit.Mvvm's WeakReferenceMessenger use to mitigate leaks?
4. What is still considered best practice even when using a weak-reference messenger?
5. What should a well-designed message class typically contain?
Was this page helpful?
You May Also Like
Dependency Injection in MVVM
How MVVM ViewModels receive their collaborators — data services, navigation, dialogs — via constructor injection instead of creating them directly, and why that makes apps testable and swappable.
Navigation in MVVM
How MVVM apps navigate between screens through an INavigationService abstraction, pass parameters and receive results, and support deep linking without ViewModels ever referencing Views.
MVVM in WPF
How WPF's data binding engine, INotifyPropertyChanged, ICommand, and value converters combine to deliver the canonical MVVM implementation the pattern was originally designed for.
Related Reading
Related Study Notes in Microsoft Technologies
Browse all study notesWindows 10 / UWP Development Study Notes
.NET · 30 topics
Microsoft TechnologiesWindows Batch Scripting Study Notes
Batch · 30 topics
Microsoft TechnologiesMFC (Microsoft Foundation Classes) Study Notes
C++ · 30 topics
Microsoft TechnologiesSilverlight Study Notes
.NET · 30 topics
Microsoft TechnologiesXAML Study Notes
.NET · 30 topics
Microsoft TechnologiesWPF (Windows Presentation Foundation) Study Notes
.NET · 30 topics