MVVM Light:如何注销 Messenger
Posted
技术标签:
【中文标题】MVVM Light:如何注销 Messenger【英文标题】:MVVM Light: how to unregister Messenger 【发布时间】:2011-07-12 12:51:58 【问题描述】:我喜欢 MVVM Light 的 Messenger 及其灵活性,但是当我忘记显式取消注册收件人(在 Silverlight 4 中)时,我遇到了内存泄漏。
原因已解释 here,但我对此很好,因为我相信无论如何明确取消注册收件人而不是依赖 Messenger 使用弱引用是一个好习惯。问题是说起来容易做起来难。
ViewModel 很简单:您通常可以完全控制它们的生命周期,并且可以在不再需要它们时 Cleanup()
它们。
Views 另一方面则比较棘手,因为它们是通过 DataTemplates 实例化和销毁的。例如。您可以将ItemsControl
和MyView
视为DataTemplate,绑定到ObservableCollection<MyViewModel>
。 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()。
你怎么看?我错过了什么明显的东西吗?
【问题讨论】:
你的这种 Cleanup() 行为也有一个模式。改为实现 IDisposable 并使用已知模式。这不会解决您的问题,但至少其他开发人员会知道您使用 Dispose() 的意图 另外,您的视图需要向 Messenger 注册任何内容的原因是什么。确定一切都会通过绑定完成吗? @Ray:视图注册了一些 viemModel 启动的操作的消息,这些操作无法通过绑定完成,例如。启动动画,设置滚动偏移(没有双向属性)等。这不是太频繁,但它会发生。 另外,我使用的是 ICleanup 而不是 IDisposable,因为这就是 MVVM-Light 的 ViewModelBase 使用的。这里有一个讨论,解释了选择背后的原因。 @Arseny:我更喜欢在视图被处理后立即取消注册,否则即使它们应该“死”,它们也可能会响应消息。同样对于弱引用,对象仍然可以存活,直到 GC 收集它(这不在我的控制之下)。 【参考方案1】:ViewModelLocator 类有助于集中存储您的视图模型。您可以使用此类来帮助管理新版本和清理旧版本。我总是通过定位器从视图中引用我的视图模型,所以我总是有可以运行的代码来管理这些东西。你可以试试。
同样,我使用 Cleanup 方法调用 Messenger.Unregister(this)
,它会清除来自该对象的信使的所有引用。你必须每次都调用 .Cleanup() ,但这就是生活 :)
【讨论】:
你能给出一个 viewmodellocator 管理版本和进行清理的代码示例吗?我很难理解……:|【参考方案2】:我没有使用过 MVVM Light(尽管我听说过很棒的事情),但如果您想要使用 WeakReferences 的 Messenger 实现,请查看此处包含的 Messenger http://mvvmfoundation.codeplex.com/。
【讨论】:
MVVM light 使用弱引用【参考方案3】:MVVM Light Messenger 正在使用 WeakAction(WeakReference)。所以你不需要显式取消注册。
【讨论】:
是的,但实验表明这还不够。请重新阅读原始问题中的所有 cmets。以上是关于MVVM Light:如何注销 Messenger的主要内容,如果未能解决你的问题,请参考以下文章