从View向ViewModel发送消息:什么是合适的令牌? [英] Send a message from View to ViewModel : what is an appropriate token?

查看:85
本文介绍了从View向ViewModel发送消息:什么是合适的令牌?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们定义:

  • a viewModel:TabViewModel
  • 视图:TabView
  • a viewModel : the TabViewModel class
  • a view : the TabView class

我有类的 n 个实例,所以有>个 n 个实例. 当TabView类的一个实例发送一条消息时,我希望它被其自己的视图模型以及仅此一个接收.

I have n instances of the TabView class, and so n instances of TabViewModel. When one instance of the TabView class send a message, I want it to be received by its own viewmodel, and only this one.

据我了解mvvm light工具包的Messenger,我应该使用类似的东西:

As I understand the Messenger of the mvvm light toolkit, I whould use something like :

// in the view
Messenger.Default.Send(new RefreshMessage(/*...*/), oneToken);

// in the viewmodel 
Messenger.Default.Register<RefreshMessage>(this, oneToken, MyViewModelMethod);

我应该为oneToken使用什么?

What should I use for oneToken ?

我的第一个想法是使用ViewModel实例作为令牌:

My first thought was to use the ViewModel instance as token :

// in the view
Messenger.Default.Send(new RefreshMessage(/*...*/), this.DataContext);

// in the viewmodel 
Messenger.Default.Register<RefreshMessage>(this, **this**, MyViewModelMethod);

对我来说,这似乎对mvvm友好",因为视图不知道什么是DataContext. 但是使用此解决方案,我担心会发生内存泄漏:在mvvm中,收件人是弱引用的,但令牌不是(如您在 Messenger类的WeakActionAndToken结构.

This seems "mvvm-friendly" to me, because the view doesn't know what is the DataContext. But with this solution, I fear a memory leak : in mvvm light, the recipients are weak-referenced, but the token is not (as you will see in the WeakActionAndToken struct of the Messenger class.

我可以用作令牌吗? viewmodel实例是一个不错的选择吗?如果使用它,如何防止内存泄漏?

选项1(基于 ethicallogics 答案):

Option 1 (based on ethicallogics answer):

  1. 在视图和视图模型上同时定义Token属性(例如,字符串或GUID类型)
  2. 定义其中一个的值(一个唯一的值,例如在viewmodel的构造函数中进行设置)
  3. 在XAML中将它们绑定在一起
  4. 在Messenger通话中使用它们

选择2(我参加过的选择):

使用viewmodel实例作为令牌.

Use the viewmodel instance as Token.

为防止内存泄漏,我们必须将其封装在weakReference中.为了与比较两个标记的Messenger配合使用,weakReference应使用Equals方法实现(WeakReference类的默认.Net实现不是这种情况).

To prevent a memory leak, we must encapsulate it in a weakReference. In order to work with the Messenger, which compares 2 tokens, the weakReference shoud have the Equals method implemented (which is not the case of the default .Net implementation of the WeakReference class).

所以我们有:

// 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类,如下所示:

I implemented the EquatableWeakReference class as follow :

/// <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是视图和视图模型上的轻量级代码,没有内存泄漏.测试成功. 如果您有更好的解决方案,请随时发表评论.

Advantage is a lightweight code on both the view and the viewmodel, with no memory leak. Tested successfully. Feel free to comment if you have a better solution.

推荐答案

令牌是View传递给ViewModel的对象唯一值,并且它们都使用相同的令牌.喜欢

Token is a object unique value that View passes to the ViewModel and they both uses the same Token. like

查看

public partial class MainWindow : Window
{
    readonly string Token;
    public MainWindow()
    {
        Token = Guid.NewGuid().ToString();
        InitializeComponent();
        DataContext = new MainViewModel(Token);
    }
}

ViewModel

ViewModel

public class MainViewModel 
{
    readonly string Token;

    public MainViewModel(string token)
    {
        Token = token;
    }
}

实际上,令牌背后的逻辑是当我们向Messenger注册一个委托时,它确实具有内部字典,并且该令牌充当该字典中的键. 视图及其ViewModel必须具有相同的令牌,以便可以在Send方法上触发与该键对应的确切委托.

Actually the logic behind the Token is that when we Register a delegate to Messenger .It does have internally dictionary and this Token act as the key in that dictionary. View and its ViewModel must have same Token So that exact delegate corresponding to that key could be fired on Send method.

这篇关于从View向ViewModel发送消息:什么是合适的令牌?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆