新答案
正如楼主(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 使用唯一标记的单个实例,因为只有接收者标记和发送者标记是完全相同的对象(而不仅仅是具有相同属性值的实例),信使才会发送消息。
原始答案(不太正确)
我认为你的问题可能有打字错误:你说要打开一个新窗口,你从ViewModel发送消息到View,但后来你又说两个ViewModel都接收到了消息。你是不是想说两个View都接收到了消息?
无论如何,如果您有两个注册了相同令牌的消息类型的实例,那么两个实例都将接收该消息。
要解决这个问题,首先需要每个ViewModel实例都有一个唯一的ID。可以使用 Guid
来实现这一点。例如:
public Guid Id { get; private set; }
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 MyViewModel ViewModel
替换 public Guid Id
,这样应该仍然可以工作。
Messenger.Default.Send<int>(Number, new MessageToken(this, Enumerators.OpenWindow.MainComent));
在我的视图中,我使用以下代码向vm注册:Messenger.Default.Register<int>(this, new MessageToken(vm, Enumerators.OpenWindow.MainComent), OpenCommentView);
消息正在发送,但是没有被接收到。 - Daryl Behrens