我喜欢MVVM Light的Messenger和其灵活性,但是当我忘记显式注销接收者时(在Silverlight 4中),就会出现内存泄漏。
原因在这里有解释,不过我认为显式注销接收者是一个好习惯,而不是依赖Messenger使用弱引用。问题是做起来比说起来难。
ViewModels很容易:通常您可以完全控制它们的生命周期,当不再需要它们时,只需
Cleanup()
即可。Views则更加棘手,因为它们通过DataTemplates进行实例化和销毁。例如,您可以将一个绑定到
ObservableCollection<MyViewModel>
的ItemsControl
使用MyView
作为DataTemplate。MyView
控件由绑定引擎创建/收集,并且您没有好的方法在其上手动调用Cleanup()。
我有一个解决方案,但想知道它是否是一个不错的模式或是否有更好的替代方案。 我的想法是从ViewModel发送特定消息,告诉相关的View(s)进行释放:
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()。
你认为呢?我有什么明显的遗漏吗?