100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
.NET

Messaging and EventAggregator

How MVVM ViewModels communicate through a decoupled publish/subscribe message bus instead of direct references, and how to avoid the memory leaks that naive implementations cause.

ArchitectureIntermediate8 min readJul 10, 2026
Analogies

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.

csharp
// 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

Was this page helpful?

Topics covered

#NET#MVVMDesignPatternStudyNotes#MicrosoftTechnologies#MessagingAndEventAggregator#Messaging#EventAggregator#Defining#Publishing#StudyNotes#SkillVeris