具有相同ViewModel的多个实例的MVVM-Light Messenger

时间:2013-08-28 00:05:24

标签: c# wpf mvvm mvvm-light

我在MVVM上相对较新,并遇到了一个问题。我们正在使用MVVM-Light框架在WPF中编写数据库应用程序。程序状态的规范我们必须能够立即打开ClaimView的多个实例。

要打开新窗口,我们将从View中捕获的ViewModel发送一条消息,然后打开新窗口。我们使用枚举令牌来识别正确的收件人以获取请求。

现在,如果我同时打开了2个ClaimView实例,并且我调用了Messanger,它会打开2个相同的窗口,因为两个视图都在接收消息。

我们尝试在单独的线程上运行ViewModel的每个实例,并通过输出ManagedThreadId进行验证,并且两个实例仍然收到消息。

我们也注册了已注册的消息,因此这不是问题。

任何帮助都将不胜感激。

1 个答案:

答案 0 :(得分:7)

新答案

正如OP(Daryl)指出的那样,我的原始答案(见下文)并不完全正确,所以我提供了一个新的答案,以防有人遇到同样的问题:

有意义的是,如果您有两个实例注册具有相同令牌的相同消息类型,则两个实例都将收到该消息。解决方案是提供每个View-ViewModel对唯一的令牌。

您可以将枚举值放在类中,而不是仅使用普通枚举值作为标记:

public class UniqueToken
{
    public MessengerToken Token { get; private set; }

    public UniqueToken(MessengerToken token)
    {
        Token = token;
    }
}

然后在ViewModel中添加一个新属性来存储其中一个唯一标记:

// add a property to your ViewModel
public UniqueToken OpenWindowToken { get; private set; }

// place this in the constructor of your ViewModel
OpenWindowToken = new UniqueToken(MessengerToken.OpenWindow);

// in the appropriate method, send the message
Messenger.Send(message, OpenWindowToken);

最后,在您的视图中,您现在可以获取唯一标记并使用它来注册OpenWindow消息:

var viewModel = (MyViewModel)DataContext;
var token = viewModel.OpenWindowToken;
Messenger.Register<TMessage>(this, token, message => OpenWindow(message));

ViewModel和View都必须使用UniqueToken的单个实例,因为如果接收者令牌和发件人令牌是完全相同的对象,信使将仅发送消息,而不仅仅是具有相同属性值的实例。


原始答案(不太正确)

我认为你的问题可能有一个拼写错误:你说打开一个新窗口,你从ViewModel向View发送一条消息,但后来你说两个 ViewModels 正在接收消息。你的意思是两个观点都收到了消息吗?

在任何情况下,如果你有两个使用相同令牌注册相同消息类型的实例,那么两个实例都将收到消息。

要解决此问题,您首先需要ViewModel的每个实例都具有唯一ID。这可以通过Guid完成。类似的东西:

// add a property to your ViewModel
public Guid Id { get; private set; }

// place this in the constructor of your ViewModel
Id = Guid.NewGuid();

然后你需要你的令牌成为一个具有两个属性的对象:一个用于guid,一个用于枚举值:

public class UniqueToken
{
    public Guid Id { get; private set; }
    public MessengerToken Token { get; private set; }

    public UniqueToken(Guid id, MessengerToken token)
    {
        Id = id;
        Token = token;
    }
}

然后当您在View中注册(或者它是您的ViewModel?)时,您需要从ViewModel中获取Guid。这可以这样工作:

var viewModel = (MyViewModel)DataContext;
var id = viewModel.Id;
var token = new UniqueToken(id, MessengerToken.OpenWindow);
Messenger.Register<TMessage>(this, token, message => OpenWindow(message));

最后,在您的ViewModel中,您需要执行以下操作:

var token = new UniqueToken(Id, MessengerToken.OpenWindow);
Messenger.Send(message, token);

修改

在输入所有内容后,我突然意识到您在ViewModel上并不需要Id属性。您可以使用ViewModel本身作为唯一标识符。因此,对于UniqueToken,您只需将public Guid Id替换为public MyViewModel ViewModel,它仍应有效。