MVVM Light: how to unregister Messenger

I love the MVVM Light's Messenger and its flexibility, however I'm experiencing memory leaks when I forget to explicitly unregister the recipients (in Silverlight 4).

The cause is explained here, but I'm fine with it as I believe it's a good practice to explicitly unregister the recipients anyways rather than relying on the Messenger's use of weak references. The problem is that is easier said than done.

  • ViewModels are easy: you usually have full control over their lifecycle and can just Cleanup() them when they are not needed anymore.

  • Views on the other hand are trickier because they are instantiated and destroyed via DataTemplates. For ex. you can think of an ItemsControl with MyView as DataTemplate, bound to an ObservableCollection<MyViewModel>. The MyView controls are created/collected by the binding engine and you have no good way to manually call Cleanup() on them.

I have a solution in mind but would like to know if it's a decent pattern or there are better alternatives. The idea is to send a specific message from the ViewModel to tell the associated View(s) to dispose:

public class MyViewModel : ViewModelBase
{
    ...

    public override void Cleanup()
    {
        // unregisters its own messages, so that we risk no leak
        Messenger.Default.Unregister<...>(this);

        // sends a message telling that this ViewModel is being cleaned
        Messenger.Default.Send(new ViewModelDisposingMessage(this));

        base.Cleanup();
    }
}

public class MyView : UserControl, ICleanup
{
    public MyView()
    {
         // registers to messages it actually needs
         Messenger.Default.Register<...>(this, DoSomething);

         // registers to the ViewModelDisposing message
         Messenger.Default.Register<ViewModelDisposingMessage>(this, m =>
             {
                 if (m.SenderViewModel == this.DataContext)
                     this.Cleanup();
             });
    }

    public void Cleanup()
    {
        Messenger.Default.Unregister<...>(this);
        Messenger.Default.Unregister<ViewModelDisposingMessage>(this);
    }
}

So when you call Cleanup() on a viewModel all the views that use it as DataContext will exeute their local Cleanup() as well.

What do you think? Am I missing something obvious?

Answers


The ViewModelLocator class helps keep a centralized store for your viewmodels. You can use this class to help manage new versions and clean up old ones. I always reference my viewmodel from view via the locator, so I always have code I can run to manage these things. You could try that.

As well, I use the Cleanup method to call Messenger.Unregister(this), which cleans up all references from the messenger for that object. You have to call .Cleanup() every time, but such is life :)


I've not used MVVM Light (though I've heard great things), but if you want a Messenger implementation that uses WeakReferences, checkout the Messenger included here http://mvvmfoundation.codeplex.com/.


MVVM Light Messenger is using WeakAction(WeakReference). So you don't need to Unregister explicitly.


Need Your Help

Concatenate numerical values in a string

string r concatenation paste cat

I would like to store this output in a string:

Transactions in the Repository Pattern

design-patterns domain-driven-design repository-pattern architectural-patterns

How do I encapsulate the saving of more than one entity in a transactional manner using the repository pattern? For example, what if I wanted to add an order and update the customer status based o...