wake-up-neo.com

MVVM Light: So entfernen Sie die Registrierung von Messenger

Ich liebe den Messenger von MVVM Light und seine Flexibilität. Allerdings erlebe ich Speicherverluste, wenn ich die Registrierung der Empfänger explizit (in Silverlight 4) vergesse.

Die Ursache wird erklärt hier , aber ich bin damit einverstanden, da es meiner Meinung nach eine gute Praxis ist, die Registrierung der Empfänger sowieso explizit aufzuheben, anstatt sich auf die Verwendung schwacher Referenzen des Messenger zu verlassen. Das Problem ist, dass es leichter gesagt als getan ist.

  • ViewModels sind einfach: Sie haben in der Regel die volle Kontrolle über ihren Lebenszyklus und können sie einfach Cleanup(), wenn sie nicht mehr benötigt werden.

  • Views sind dagegen schwieriger, weil sie über DataTemplates instanziiert und zerstört werden. Für ex. Sie können sich eine ItemsControl mit MyView als DataTemplate vorstellen, die an einen ObservableCollection<MyViewModel> gebunden ist. Die MyView-Steuerelemente werden vom Bindungsmodul erstellt/gesammelt, und Sie können Cleanup () nicht manuell aufrufen.

Ich habe eine Lösung im Sinn, möchte aber gerne wissen, ob es sich um ein anständiges Muster handelt oder ob es bessere Alternativen gibt. Die Idee ist, eine bestimmte Nachricht aus dem ViewModel zu senden, um die zugehörigen View (s) zur Verfügung zu stellen:

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);
    }
}

Wenn Sie also Cleanup () für ein viewModel aufrufen, werden alle Ansichten, die es als DataContext verwenden, auch deren lokales Cleanup () exeute.

Was denkst du? Fehlt mir etwas offensichtliches?

42

Mit der ViewModelLocator-Klasse können Sie einen zentralen Speicher für Ihre Ansichtsmodelle verwalten. Mit dieser Klasse können Sie neue Versionen verwalten und alte Versionen bereinigen. Ich verweise mein Viewmodel immer über den Locator aus der Sicht, so dass ich immer Code habe, den ich ausführen kann, um diese Dinge zu verwalten. Das könntest du versuchen.

Außerdem benutze ich die Cleanup-Methode, um Messenger.Unregister(this) aufzurufen, die alle Verweise auf den Messenger für dieses Objekt löscht. Sie müssen jedes Mal .Cleanup () aufrufen, aber so ist das Leben :)

6
CamronBute

Ich habe MVVM Light nicht verwendet (obwohl ich tolle Dinge gehört habe), aber wenn Sie eine Messenger-Implementierung wünschen, die WeakReferences verwendet, checken Sie den Messenger hier http://mvvmfoundation.codeplex.com/ .

1
BrandonZeider

MVVM Light Messenger verwendet WeakAction (WeakReference). Sie müssen die Registrierung daher nicht explizit aufheben.

0
wafe