42 votes

MVVM Light: comment désenregistrer Messenger

J'aime le MVVM Light et de son Messager et sa souplesse, cependant je suis en train de vivre des fuites de mémoire quand j'oublie explicitement annuler l'inscription des bénéficiaires (dans Silverlight 4).

La cause en est expliqué ici, mais je suis très bien avec lui que je crois que c'est une bonne pratique explicitement annuler l'inscription des bénéficiaires de toute façon, plutôt que de compter sur le Messager de l'utilisation de références faibles. Le problème est que c'est plus facile à dire qu'à faire.

  • Viewmodel sont faciles: généralement, vous avez le plein contrôle sur leur cycle de vie et peuvent seulement Cleanup() quand ils ne sont plus nécessaires.

  • Points de vue sur l'autre main sont plus difficiles parce qu'ils sont instanciés et détruit par DataTemplates. Pour ex. vous pouvez penser à un ItemsControl avec MyView comme DataTemplate, lié à un ObservableCollection<MyViewModel>. L' MyView des contrôles sont créés, recueillis par le moteur de liaison et vous n'avez pas de bonne façon de manuellement appel Cleanup() sur eux.

J'ai une solution à l'esprit mais je voudrais savoir si c'est un décent motif ou il y a de meilleures alternatives. L'idée est d'envoyer un message à partir de ce Dernier de dire à la Vue associée(s) à éliminer:

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

Ainsi, lorsque vous appelez Cleanup() sur un viewModel tous les points de vue de l'utiliser comme DataContext sera exeute leur local de Nettoyage() ainsi.

Qu'en pensez-vous? Ai-je raté quelque chose d'évident?

6voto

CamronBute Points 505

La classe ViewModelLocator permet de conserver un magasin centralisé pour vos modèles de vue. Vous pouvez utiliser cette classe pour vous aider à gérer les nouvelles versions et à nettoyer les anciennes. Je fais toujours référence à mon modèle de vue depuis le localisateur, de sorte que je dispose toujours du code que je peux exécuter pour gérer ces éléments. Tu pourrais essayer ça.

De plus, j'utilise la méthode de nettoyage pour appeler Messenger.Unregister(this) , ce qui nettoie toutes les références du messager pour cet objet. Vous devez appeler .Cleanup () à chaque fois, mais telle est la vie :)

1voto

BrandonZeider Points 4692

Je n'ai pas utilisé MVVM Light (bien que j'aie entendu de bonnes choses), mais si vous voulez une implémentation de Messenger qui utilise WeakReferences, consultez le Messenger inclus ici http://mvvmfoundation.codeplex.com/ .

0voto

wafe Points 1

MVVM Light Messenger utilise WeakAction (WeakReference). Donc, vous n'avez pas besoin de vous désinscrire explicitement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X