让我们定义:
- 一个 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 中,接收者是弱引用的,但令牌不是(正如您将在Messenger 类的 WeakActionAndToken 结构中看到的那样。
我可以用什么作为令牌?viewmodel 实例是一个不错的选择吗?如果使用它,如何防止内存泄漏?
编辑:可能的解决方案
选项 1(基于伦理逻辑的答案):
- 在视图和视图模型上定义一个 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 是视图和视图模型上的轻量级代码,没有内存泄漏。测试成功。如果您有更好的解决方案,请随时发表评论。