5

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

为了打开新窗口,我们从 ViewModel 中发送一条消息,该消息被 View 捕获,并打开新窗口。我们正在使用枚举令牌来识别正确的接收者来获取请求。

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

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

我们也取消了注册消息的注册,所以这不是问题。

任何帮助,将不胜感激。

4

1 回答 1

9

新答案

正如 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 发送一条消息,但后来您说两个ViewModel都在接收该消息。您的意思是两个视图都在接收消息吗?

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

为了解决这个问题,你首先需要你的 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;
    }
}

然后当你在你的视图中注册时(或者它是你的视图模型?),你需要从视图模型中获取 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);

编辑

输入所有内容后,我突然想到您实际上并不需要IdViewModel 上的属性。您可以只使用 ViewModel 本身作为唯一标识符。因此,对于UniqueToken,您可以只替换public Guid Idpublic MyViewModel ViewModel,它应该仍然可以工作。

于 2013-08-28T01:08:20.920 回答