MVVM Light:如何取消注册Messenger

时间:2011-03-10 08:12:15

标签: c# silverlight mvvm silverlight-4.0 mvvm-light

我喜欢MVVM Light的Messenger及其灵活性,但是当我忘记明确取消注册收件人时(在Silverlight 4中),我遇到了内存泄漏。

原因解释here,但我很好,因为我认为明确取消注册收件人是一个好习惯,而不是依赖于Messenger使用弱引用。问题是说起来容易做起来难。

  • ViewModels 非常简单:您通常可以完全控制其生命周期,只有Cleanup()不再需要它们。

  • 另一方面,
  • 视图比较棘手,因为它们是通过DataTemplates实例化和销毁的。对于前者您可以将ItemsControlMyView视为DataTemplate,绑定到ObservableCollection<MyViewModel>MyView控件由绑定引擎创建/收集,您无法手动调用它们上的Cleanup()。

我有一个解决方案,但想知道它是否是一个体面的模式或有更好的选择。 我们的想法是从ViewModel发送一条特定的消息来告诉相关的View处置:

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

因此,当您在viewModel上调用Cleanup()时,所有将其用作DataContext的视图也将执行其本地Cleanup()。

你怎么看?我错过了一些明显的东西吗?

3 个答案:

答案 0 :(得分:6)

ViewModelLocator类有助于为视图模型保留集中存储。您可以使用此类来帮助管理新版本并清理旧版本。我总是通过定位器从视图中引用我的viewmodel,所以我总是有可以运行的代码来管理这些东西。你可以试试。

同样,我使用Cleanup方法调用Messenger.Unregister(this),它清除来自该对象的信使的所有引用。你必须每次都调用.Cleanup(),但这就是生活:)

答案 1 :(得分:1)

我没有使用MVVM Light(虽然我听过很棒的东西)但是如果你想要一个使用WeakReferences的Messenger实现,请查看这里包含的Messenger http://mvvmfoundation.codeplex.com/

答案 2 :(得分:0)

MVVM Light Messenger正在使用WeakAction(WeakReference)。因此,您无需显式取消注册。