Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
github avatar

Mvvm Toolkit Messenger

  • 1 installs
  • 37.5k repo stars
  • Updated August 5, 2026
  • github/awesome-copilot

mvvm-toolkit-messenger skill documents CommunityToolkit.

About

mvvm-toolkit-messenger skill documents CommunityToolkit.Mvvm Messenger pub/sub for decoupled communication between ViewModels (or any objects). Covers WeakReferenceMessenger vs StrongReferenceMessenger, IRecipient<TMessage>, RequestMessage<T> / AsyncRequestMessage<T> / CollectionRequestMessage<T>, ValueChangedMessage<T>, channels (tokens. name: mvvm-toolkit-messenger description: 'CommunityToolkit.Mvvm Messenger pub/sub for decoupled communication between ViewModels (or any objects). Covers WeakReferenceMessenger vs StrongReferenceMessenger, IRecipient<TMessage>, RequestMessage<T> / AsyncRequestMessage<T> / CollectionRequestMessage<T>, ValueChangedMessage<T>, channels (tokens), and the ObservableRecipient activation lifecycle. Use

  • CommunityToolkit.
  • Platform-specific setup patterns for mvvm-toolkit-messenger.
  • Evidence-backed steps from upstream SKILL.md.
  • When-to-use criteria for mvvm-toolkit-messenger versus alternatives.

Mvvm Toolkit Messenger by the numbers

  • 1 all-time installs (skills.sh)
  • Ranked #1,980 of 2,715 Automation & Workflows skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
At a glance

mvvm-toolkit-messenger capabilities & compatibility

Capabilities
mvvm toolkit messenger quick start · mvvm toolkit messenger when to use guidance · mvvm toolkit messenger integration patterns
From the docs

What mvvm-toolkit-messenger says it does

Pub/sub messaging for ViewModels (or any objects) without forcing a shared
SKILL.md
reference graph. Part of `CommunityToolkit.Mvvm` 8.x.
SKILL.md
npx skills add https://github.com/github/awesome-copilot --skill mvvm-toolkit-messenger

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs1
repo stars37.5k
Last updatedAugust 5, 2026
Repositorygithub/awesome-copilot

How do I use mvvm-toolkit-messenger correctly?

CommunityToolkit.Mvvm Messenger pub/sub for decoupled communication between ViewModels (or any objects). Covers WeakReferenceMessenger vs StrongReferenceMessenger, IRecipient<TMessage>, RequestMessage

Who is it for?

Teams implementing mvvm-toolkit-messenger workflows from the catalog.

Skip if: Skip when requirements clearly match a different specialized stack.

When should I use this skill?

User asks about mvvm-toolkit-messenger, communitytoolkit.mvvm messenger pub/sub for decoupled communication between viewmodels (or.

What you get

Working mvvm-toolkit-messenger setup with validated configuration and next steps.

Files

SKILL.mdMarkdownGitHub ↗

CommunityToolkit.Mvvm Messenger

Pub/sub messaging for ViewModels (or any objects) without forcing a shared reference graph. Part of CommunityToolkit.Mvvm 8.x.

TL;DR. Default to WeakReferenceMessenger.Default. Register handlers
with the (recipient, message) lambda and the static modifier so you
never capture this. Inherit from ObservableRecipient and toggle
IsActive at activation/deactivation to get automatic register/unregister.

---

When to use this skill

  • Two or more ViewModels need to react to an event (login, theme change,

save, navigation) without holding references to each other

  • A ViewModel needs to ask another VM for a value (request/reply)
  • You're scoping events to a sub-system or window with channel tokens
  • Diagnosing "my handler never fires" or weak-reference recipient lifetime

problems

For source generators, base classes, and commands see the `mvvm-toolkit` skill. For DI wiring (registering an IMessenger instance), see `mvvm-toolkit-di`.

---

Choose an implementation

TypeWhen
WeakReferenceMessenger.DefaultDefault. Recipients held weakly — eligible for GC even while registered. Internal trimming runs during full GCs; no manual Cleanup() needed.
StrongReferenceMessenger.DefaultProfiler shows the messenger is hot and allocation matters. Recipients are pinned until you Unregister. Forgetting unregistration leaks them.
Custom IMessenger instancePer-window/per-scope (e.g., one messenger per app window). Construct directly, inject via DI.

ObservableRecipient's parameterless constructor uses WeakReferenceMessenger.Default. Pass a different IMessenger to its constructor to override.

---

Define a message

The toolkit ships base classes; any class works.

using CommunityToolkit.Mvvm.Messaging.Messages;

// Single-payload broadcast
public sealed class LoggedInUserChangedMessage(User user)
    : ValueChangedMessage<User>(user);

// Custom shape (records are great for this)
public sealed record ThemeChangedMessage(AppTheme NewTheme);

// Empty signal
public sealed record RefreshRequestedMessage;

---

Register a recipient

Lambda style (recommended)

WeakReferenceMessenger.Default.Register<MyViewModel, ThemeChangedMessage>(
    this,
    static (recipient, message) => recipient.OnThemeChanged(message.NewTheme));

The static modifier prevents accidental closure allocation and keeps this out of the lambda — use the recipient parameter instead.

IRecipient<TMessage> interface style

public sealed class MyViewModel : ObservableRecipient,
    IRecipient<ThemeChangedMessage>,
    IRecipient<RefreshRequestedMessage>
{
    public void Receive(ThemeChangedMessage message) { /* ... */ }
    public void Receive(RefreshRequestedMessage message) { /* ... */ }
}

ObservableRecipient.OnActivated() calls Messenger.RegisterAll(this), which subscribes every IRecipient<T> interface implemented by the type. If you're not using ObservableRecipient, register manually:

WeakReferenceMessenger.Default.RegisterAll(this);

---

Send a message

WeakReferenceMessenger.Default.Send(new ThemeChangedMessage(AppTheme.Dark));

// Empty payloads use the parameterless overload:
WeakReferenceMessenger.Default.Send<RefreshRequestedMessage>();

---

Channels (tokens)

Scope messages to a sub-system or window with a token (any equatable value — int, string, Guid):

const int LeftPaneChannel = 1;

WeakReferenceMessenger.Default.Register<MyViewModel, RefreshRequestedMessage, int>(
    this, LeftPaneChannel,
    static (r, _) => r.RefreshLeft());

WeakReferenceMessenger.Default.Send(new RefreshRequestedMessage(), LeftPaneChannel);

Messages sent without a token use the default shared channel — they are not delivered to channel-scoped recipients.

---

Request / reply

For ask-style scenarios where a recipient provides a value back to the sender, use the RequestMessage<T> family.

Sync request

public sealed class CurrentUserRequest : RequestMessage<User> { }

WeakReferenceMessenger.Default.Register<UserService, CurrentUserRequest>(
    this,
    static (r, m) => m.Reply(r.CurrentUser));

User user = WeakReferenceMessenger.Default.Send<CurrentUserRequest>();

The implicit conversion from CurrentUserRequest to User throws if no recipient called Reply. Capture the message to check first:

var request = WeakReferenceMessenger.Default.Send<CurrentUserRequest>();
if (request.HasReceivedResponse)
    User user = request.Response;

Async request

public sealed class CurrentUserRequest : AsyncRequestMessage<User> { }

WeakReferenceMessenger.Default.Register<UserService, CurrentUserRequest>(
    this,
    static (r, m) => m.Reply(r.GetCurrentUserAsync()));

User user = await WeakReferenceMessenger.Default.Send<CurrentUserRequest>();

Collection requests (fan-in)

CollectionRequestMessage<T> and AsyncCollectionRequestMessage<T> collect a Reply from every responding recipient:

public sealed class OpenDocumentsRequest : CollectionRequestMessage<Document> { }

var docs = WeakReferenceMessenger.Default.Send<OpenDocumentsRequest>();
foreach (Document doc in docs) { /* ... */ }

---

Lifecycle

Even with WeakReferenceMessenger, unregister explicitly when a recipient is being torn down — it trims dead entries and improves performance:

WeakReferenceMessenger.Default.Unregister<ThemeChangedMessage>(this);
WeakReferenceMessenger.Default.Unregister<ThemeChangedMessage, int>(this, LeftPaneChannel);
WeakReferenceMessenger.Default.UnregisterAll(this);

ObservableRecipient.OnDeactivated() does this automatically when IsActive flips to false. Set it from your activation hook:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);
    ViewModel.IsActive = true;
}

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    ViewModel.IsActive = false;
    base.OnNavigatedFrom(e);
}

---

Common pitfalls

1. Capturing `this` in the lambda. (r, m) => OnX(m) implicitly captures this; allocates a closure and confuses lifetime. Always use (r, m) => r.OnX(m) with static. 2. Strong-ref recipients without `Unregister`. With StrongReferenceMessenger, recipients (and their entire object graph) stay pinned forever. Either inherit from ObservableRecipient (auto-unregisters in OnDeactivated) or call UnregisterAll(this). 3. Inherited message types. A handler registered for BaseMessage is not invoked for DerivedMessage : BaseMessage. Register each concrete type. 4. Wrong messenger instance. Sending via WeakReferenceMessenger.Default and registering via an injected per-window messenger means the message never arrives. Use the same IMessenger everywhere (typically inject it via ObservableRecipient(messenger)). 5. `OnActivated` never runs. ObservableRecipient only registers IRecipient<T> handlers when IsActive flips from false to true. 6. Cross-thread updates. The messenger is thread-agnostic. If a handler updates UI, marshal manually (DispatcherQueue.TryEnqueue / Dispatcher.BeginInvoke).

---

Multiple messengers (per-window scoping)

services.AddSingleton<IMessenger>(WeakReferenceMessenger.Default); // app-wide
services.AddScoped<WindowScopedMessenger>();                       // per-window

Inject the appropriate IMessenger into the ViewModel constructor:

public sealed partial class WindowViewModel(IMessenger messenger)
    : ObservableRecipient(messenger) { }

This isolates broadcasts to a single window — useful for multi-window desktop apps (WinUI 3, WPF, MAUI desktop, Avalonia).

---

References

TopicFile
Full deep dive (more channel/lifecycle examples, diagnostics)`references/messenger-patterns.md`

External:

  • Messenger docs: <https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/messenger>
  • WeakReferenceMessenger API: <https://learn.microsoft.com/en-us/dotnet/api/communitytoolkit.mvvm.messaging.weakreferencemessenger>
  • Source: <https://github.com/CommunityToolkit/dotnet>

Related skills

FAQ

What does mvvm-toolkit-messenger do?

mvvm-toolkit-messenger skill documents CommunityToolkit.

When should I use mvvm-toolkit-messenger?

User asks about mvvm-toolkit-messenger, communitytoolkit.mvvm messenger pub/sub for decoupled communication between viewmodels (or.

Is this skill safe to install?

Review the Security Audits panel on this page before installing in production.

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.