MVVM Light Messenger重复接收消息问题求助
Hey there! Let's break down why your Messenger is firing multiple times even after you've tried unsubscribing, and how to fix it.
First, Let's Diagnose the Root Cause
From what you described, the _recipientStrictAction dictionary having duplicate tokens tells us old ViewModel subscriptions aren't being fully removed. Since all your ViewModels are singletons, the most likely culprit is that old ViewModel instances are still lingering in memory (held by unintended references), and each new "rebuild" adds a fresh subscription on top of the old ones.
Common Mistakes & Fixes
1. Ensure Your Singleton ViewModels Are Actually Singletons
Double-check your ViewModelLocator registration logic. Even with SimpleIoc.Default.Register<T>(true) (which enables singleton mode), if you're accidentally re-registering the ViewModel elsewhere, you could end up with multiple instances. Add a debug log in your ViewModel constructor to confirm:
public HomeViewModel() { Debug.WriteLine($"HomeViewModel instance created - Hash: {GetHashCode()}"); Messenger.Default.Register<SimpleMessage>(this, ViewModelName, ProcessMessage); }
If you see multiple hash codes logged, you're creating duplicate instances. Fix this by making sure your ViewModelLocator only registers each ViewModel once, and that navigation/initialization logic doesn't spawn new instances.
2. Fix Your Unregistration Logic
Your current UnRegisterViewModel method is on the right track, but it might be missing key steps:
- Always call cleanup from the ViewModel itself: Override the
Cleanupmethod in your baseViewModelTemplateto guarantee unsubscription happens, even if the external unregister method is missed:public abstract class ViewModelTemplate : ViewModelBase { public abstract string ViewModelName { get; } public override void Cleanup() { // Unsubscribe from ALL message types this ViewModel listens to Messenger.Default.Unregister<SimpleMessage>(this, ViewModelName); // Add other message types here if needed base.Cleanup(); } } - Ensure no references hold onto old ViewModels: After unregistering from the IoC container, make sure all bindings, event handlers, or static references to the old ViewModel are cleared. If something still holds a reference, the GC won't collect it, and its Messenger subscription will stay active.
3. Verify Token Matching
Double-check that the token used to register (ViewModelName) exactly matches the token used to send (ViewModelNameEnum.Home). For example:
- If
ViewModelNameis a string like"Home", ensureViewModelNameEnum.Home.ToString()returns the exact same string (no case mismatches, typos, or extra whitespace). - Consider using the enum value directly as the token instead of a string to eliminate matching errors:
// Register with enum token Messenger.Default.Register<SimpleMessage>(this, ViewModelNameEnum.Home, ProcessMessage); // Send with the same enum token Messenger.Default.Send(message, ViewModelNameEnum.Home);
4. A Last Resort: Manual Subscription Cleanup (Not Recommended Long-Term)
If you need an immediate fix while you track down the reference leak, you can use reflection to manually remove stale subscriptions (note: this relies on MVVM Light's internal structure, which could change):
using System.Reflection; // Clear all subscriptions for a specific token and message type var messengerInstance = Messenger.Default; var recipientField = typeof(Messenger).GetField("_recipientStrictAction", BindingFlags.NonPublic | BindingFlags.Instance); if (recipientField == null) return; var recipientDict = recipientField.GetValue(messengerInstance) as Dictionary<Type, Dictionary<object, Dictionary<object, Delegate>>>; if (recipientDict?.ContainsKey(typeof(SimpleMessage)) == true) { var tokenDict = recipientDict[typeof(SimpleMessage)]; tokenDict.Remove(ViewModelNameEnum.Home); // Use your exact token here }
Key Takeaway
The core issue is almost always lingering ViewModel instances that weren't properly garbage collected, leaving their Messenger subscriptions active. Focus on ensuring:
- Only one instance of each ViewModel exists at a time
- Every ViewModel's
Cleanupmethod unsubscribes from all messages - No unintended references hold onto old ViewModel instances
内容的提问来源于stack exchange,提问作者Speuline

