【发布时间】:2014-01-04 14:24:41
【问题描述】:
让我们定义:
- viewModel:
TabViewModel类 - 一个视图:
TabView类
我有 n 个 TabView 类的实例,以及 n 个TabViewModel 的实例。
当TabView 类的一个实例发送一条消息时,我希望它被它自己的视图模型接收,只有这个。
据我了解 mvvm light 工具包的 Messenger,我应该使用类似的东西:
// in the view
Messenger.Default.Send(new RefreshMessage(/*...*/), oneToken);
和
// in the viewmodel
Messenger.Default.Register<RefreshMessage>(this, oneToken, MyViewModelMethod);
oneToken 应该使用什么?
我的第一个想法是使用 ViewModel 实例作为令牌:
// in the view
Messenger.Default.Send(new RefreshMessage(/*...*/), this.DataContext);
和
// in the viewmodel
Messenger.Default.Register<RefreshMessage>(this, **this**, MyViewModelMethod);
这对我来说似乎是“mvvm-friendly”,因为视图不知道 DataContext 是什么。 但是有了这个解决方案,我担心内存泄漏:在 mvvm light 中,收件人是弱引用的,但令牌不是(正如您将在 WeakActionAndToken struct of the Messenger class 中看到的那样。
我可以使用什么作为令牌?视图模型实例是不是一个不错的选择,如果我使用它如何防止内存泄漏?
编辑:可能的解决方案
选项 1(基于 ethicallogics 答案):
- 在视图和视图模型上定义一个 Token 属性(例如字符串或 GUID 类型)
- 定义其中一个的值(唯一值,例如在视图模型的构造函数中设置)
- 在 XAML 中将它们绑定在一起
- 在 Messenger 通话中使用它们
选项 2(我采用的那个):
使用 viewmodel 实例作为 Token。
为了防止内存泄漏,我们必须将它封装在一个弱引用中。为了与比较 2 个令牌的 Messenger 一起工作,weakReference 应该实现 Equals 方法(这不是 WeakReference 类的默认 .Net 实现的情况)。
所以我们有:
// in the view
Messenger.Default.Send(new RefreshMessage(), new EquatableWeakReference(this.DataContext));
和
// in the viewmodel
Messenger.Default.Register<RefreshMessage>(this, new EquatableWeakReference(this), ApplyRefreshMessage);
我实现了EquatableWeakReference 类如下:
/// <summary>
/// A weak reference which can be compared with another one, based on the target comparison.
/// </summary>
public class EquatableWeakReference : IEquatable<EquatableWeakReference>
{
private WeakReference reference;
private int targetHashcode;
public EquatableWeakReference(object target)
{
if (target == null)
throw new ArgumentNullException("target");
reference = new WeakReference(target);
targetHashcode = target.GetHashCode();
}
public override bool Equals(object obj)
{
return Equals(obj as EquatableWeakReference);
}
/// <summary>
/// As Equals is overriden, we must provide an override for GetHashCode.
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return targetHashcode;
}
public bool Equals(EquatableWeakReference other)
{
if (other == null
|| !reference.IsAlive
|| !other.reference.IsAlive)
return false; // we assume that if both references are not alive, the result is inconclusive : let's say false.
return this.reference.Target.Equals(other.reference.Target);
}
}
Advantage 是视图和视图模型上的轻量级代码,没有内存泄漏。测试成功。 如果您有更好的解决方案,请随时发表评论。
【问题讨论】:
标签: c# wpf mvvm mvvm-light messenger