MVVM Light:如何取消注册Messenger

我喜欢MVVM Light的Messenger以及它的灵活性,但是当我忘记明确注销收件人(在Silverlight 4中)时,我正在经历内存泄漏。

原因在这里解释,但我很好,因为我相信这是一个很好的做法,明确注销收件人,而不是依靠信使的弱引用。 问题在于说起来容易做起来难。

  • ViewModel很容易:你通常可以完全控制它们的生命周期,并且可以在不再需要的时候Cleanup()它们。

  • 另一方面, 视图更复杂,因为它们通过DataTemplates实例化和销毁。 例如。 你可以将MyViewItemsControl视为DataTemplate,绑定到ObservableCollection<MyViewModel>MyView控件是由绑定引擎创build/收集的,您无法手动调用它们的Cleanup()。

我有一个解决scheme,但想知道这是一个体面的模式,还是有更好的select。 这个想法是从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()。

你怎么看? 我错过了什么明显的?

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

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

我没有使用MVVM Light(尽pipe我听说过很棒的东西),但是如果你想要一个使用WeakReferences的Messenger实现,可以在这里http://mvvmfoundation.codeplex.com/查看Messenger。;

MVVM Light Messenger正在使用WeakAction(WeakReference)。 所以你不需要明确注销。