MVVMLight 信使有作用域吗?
Does the MVVMLight messenger have scope?
想象一个 WPF 应用程序,其中一个主视图代表一个 window,可以多次打开。这个主视图有几个子视图。
信使可以在主视图的视图模型及其子视图的视图模型之间发送消息。
是否可以将 Messenger 限制在一个范围内,这样如果您打开了两个主视图,与其中一个交互时只会向该视图的子视图发送消息?
是否有另一种方法可以在父视图模型和子视图模型之间以尊重 MVVM 的方式共享 "identity"?
您可以使用“令牌”的概念来实现此效果。
IMessenger
接口有 Register
和 Send
的重载,它们接受一个对象来限制哪些注册者接收消息。如果使用令牌发送消息,则将看到该消息的唯一对象是使用相同令牌注册该消息的对象。在这里,“相同”表示对象相等,因此您可以使用任何具有合理相等语义且对您有意义的对象作为令牌,即 GUID、整数或字符串。
例如,考虑以下对象:
public static class MessengerHelper
{
public static IMessenger Messenger { get { return GalaSoft.MvvmLight.Messaging.Messenger.Default; } }
public static object Group1Token { get { return 1; } }
public static object Group2Token { get { return 2; } }
}
public class FooChild
{
object token;
public FooChild(object token)
{
this.token = token;
MessengerHelper.Messenger.Register<IFooMessage>(this, token, HandleFooMessage);
}
void HandleFooMessage(IFooMessage fooMessage)
{
Console.WriteLine("FooChild got the message, token = " + (token ?? "(null)"));
}
}
public class FooParent
{
FooChild[] children;
public FooParent()
{
children = new [] {
new FooChild(MessengerHelper.Group1Token),
new FooChild(MessengerHelper.Group2Token),
new FooChild(null)
};
}
public void SendFooMessage(IFooMessage fooMessage, object token)
{
MessengerHelper.Messenger.Send(fooMessage, token);
}
}
然后,如果您创建父级并使用给定的标记发送消息:
FooParent parent = new FooParent();
parent.SendFooMessage(new FooMessage(), MessengerHelper.Group1Token);
parent.SendFooMessage(new FooMessage(), MessengerHelper.Group2Token);
您将得到以下输出:
FooChild got the message, token = 1
FooChild got the message, token = 2
在您的情况下,您希望每个主视图模型都有自己的令牌,并将它们的令牌传递给它们的子视图模型。
您始终可以在传递默认值 IMessenger
之间做出选择,后者将具有 static、应用程序域范围或创建新的 Messenger 实例:
var domainWideMessenger = GalaSoft.MvvmLight.Messaging.Messenger.Default;
var localMessenger = new Messenger();
当您不想控制 Messenger 的范围时,第一种方法很有用。您可以将其视为中心枢纽。 "local" Messenger 适用于 VM 内或某些容器内的通信。
为什么这可能比拥有代币更好?!当您拥有基于令牌的消息传递的高级应用程序时,在某些时候您将面临处理它们的困难(选择正确的)。特别是在依赖注入方面。
在您的情况下,您将拥有每个 MainView
的 Messenger
的新实例,该实例将被下推到其所有子视图和视图模型。要同步数据并在 MainView
的多个实例之间进行通信,请使用来自 MVVM Light 的静态 Messenger
。
想象一个 WPF 应用程序,其中一个主视图代表一个 window,可以多次打开。这个主视图有几个子视图。
信使可以在主视图的视图模型及其子视图的视图模型之间发送消息。
是否可以将 Messenger 限制在一个范围内,这样如果您打开了两个主视图,与其中一个交互时只会向该视图的子视图发送消息?
是否有另一种方法可以在父视图模型和子视图模型之间以尊重 MVVM 的方式共享 "identity"?
您可以使用“令牌”的概念来实现此效果。
IMessenger
接口有 Register
和 Send
的重载,它们接受一个对象来限制哪些注册者接收消息。如果使用令牌发送消息,则将看到该消息的唯一对象是使用相同令牌注册该消息的对象。在这里,“相同”表示对象相等,因此您可以使用任何具有合理相等语义且对您有意义的对象作为令牌,即 GUID、整数或字符串。
例如,考虑以下对象:
public static class MessengerHelper
{
public static IMessenger Messenger { get { return GalaSoft.MvvmLight.Messaging.Messenger.Default; } }
public static object Group1Token { get { return 1; } }
public static object Group2Token { get { return 2; } }
}
public class FooChild
{
object token;
public FooChild(object token)
{
this.token = token;
MessengerHelper.Messenger.Register<IFooMessage>(this, token, HandleFooMessage);
}
void HandleFooMessage(IFooMessage fooMessage)
{
Console.WriteLine("FooChild got the message, token = " + (token ?? "(null)"));
}
}
public class FooParent
{
FooChild[] children;
public FooParent()
{
children = new [] {
new FooChild(MessengerHelper.Group1Token),
new FooChild(MessengerHelper.Group2Token),
new FooChild(null)
};
}
public void SendFooMessage(IFooMessage fooMessage, object token)
{
MessengerHelper.Messenger.Send(fooMessage, token);
}
}
然后,如果您创建父级并使用给定的标记发送消息:
FooParent parent = new FooParent();
parent.SendFooMessage(new FooMessage(), MessengerHelper.Group1Token);
parent.SendFooMessage(new FooMessage(), MessengerHelper.Group2Token);
您将得到以下输出:
FooChild got the message, token = 1
FooChild got the message, token = 2
在您的情况下,您希望每个主视图模型都有自己的令牌,并将它们的令牌传递给它们的子视图模型。
您始终可以在传递默认值 IMessenger
之间做出选择,后者将具有 static、应用程序域范围或创建新的 Messenger 实例:
var domainWideMessenger = GalaSoft.MvvmLight.Messaging.Messenger.Default;
var localMessenger = new Messenger();
当您不想控制 Messenger 的范围时,第一种方法很有用。您可以将其视为中心枢纽。 "local" Messenger 适用于 VM 内或某些容器内的通信。
为什么这可能比拥有代币更好?!当您拥有基于令牌的消息传递的高级应用程序时,在某些时候您将面临处理它们的困难(选择正确的)。特别是在依赖注入方面。
在您的情况下,您将拥有每个 MainView
的 Messenger
的新实例,该实例将被下推到其所有子视图和视图模型。要同步数据并在 MainView
的多个实例之间进行通信,请使用来自 MVVM Light 的静态 Messenger
。