【问题标题】:Does the MVVMLight messenger have scope?MVVMLight Messenger 有作用域吗?
【发布时间】:2015-07-20 20:02:00
【问题描述】:

想象一个 WPF 应用程序,其中一个主视图代表一个可以多次打开的窗口。这个主视图有几个子视图。

信使可以在主视图的视图模型与其子视图的视图模型之间发送消息。

是否可以使信使的范围受到限制,这样如果您打开了两个主视图,与一个主视图交互时只会向该视图的子视图发送消息?

是否有另一种方法可以在父视图模型和子视图模型之间共享“身份”以尊重 MVVM?

【问题讨论】:

    标签: c# wpf mvvm-light


    【解决方案1】:

    您始终可以在传递默认IMessenger 之间进行选择,该IMessenger 将具有静态、应用程序域范围或创建新的信使实例:

    var domainWideMessenger = GalaSoft.MvvmLight.Messaging.Messenger.Default;
    var localMessenger = new Messenger();
    

    当您不想控制信使的范围时,第一种方法很有用。您可以将其视为中心枢纽。 “本地”信使适用于 VM 内或某些容器内的通信。

    为什么这可能比拥有令牌更好?!当您在某些时候拥有带有基于令牌的消息传递的高级应用程序时,您将面临处理它们的困难(选择正确的)。尤其是在依赖注入方面。

    在您的情况下,您将拥有每个 MainViewMessenger 的新实例,该实例将被推送到其所有子视图和视图模型。要在 MainView 的多个实例之间同步数据并进行通信,请使用 MVVM Light 中的静态 Messenger

    【讨论】:

    • 正是问题所在。这不仅仅是让信使进入,而是确保 DI 智能地做到这一点。所以我仍然需要想一个方案来让 DI 创建/选择正确的信使。
    【解决方案2】:

    您可以使用“令牌”的概念来实现此效果。

    IMessenger 接口有 RegisterSend 的重载,它们接受一个对象来限制哪些注册者接收消息。如果使用令牌发送消息,则可以看到该消息的唯一对象是那些使用相同令牌注册消息的对象。在这里,“相同”表示对象相等,因此您可以将任何对象用作具有合理相等语义并且对您有意义的标记,即 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 得到消息,token = 1

    FooChild 得到消息,token = 2

    在您的情况下,您会希望每个主视图模型都有自己的标记,并将它们的标记传递给它们的子视图模型。

    【讨论】:

    • 您的回答比我提出的问题要好:) 为了保持简单,我省略了 DI 方面。所以这种方法效果很好,但是我的 DI 不能自动选择正确的标记。
    • 对于 DI 部分,您可以定义一个工厂来创建您的子视图模型。请参阅Castle Windsor's 实现。
    猜你喜欢
    • 1970-01-01
    • 2011-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多