【问题标题】:MVVMLight : is this the right way to use the Messenger?MVVMLight:这是使用 Messenger 的正确方法吗?
【发布时间】:2011-07-26 20:26:27
【问题描述】:

我有一个管理客户和地址的经典业务应用程序。

选项卡项(Id、GenericInfo 等)各有自己的 ViewModel。

有一个 MainViewModel 处理客户端及其地址的保存和加载命令。

我们从 WCF 服务中检索数据。从每个 WCF 函数接收/发送的数据聚合在不同的容器中。


在我的 MainViewModel 中,我创建了一个 SaveContainer,然后将其与信使一起发送。

    public void Save()
    {
        var container = new SaveContainer();

        MessengerInstance.Send(container);

        //the container is now populated and ready to be sent via WCF

        Console.WriteLine(container.User.Name);
        Console.WriteLine(container.Address.StreetName);
        Console.WriteLine(container.Address2.StreetName);
    }

在我的 UserViewModel 中为该容器注册,然后 viewmodel 用它拥有的数据(用户)填充它。

    public UserViewModel()
        : base(Messenger.Default)
    {
        User = new User();

        MessengerInstance.Register<SaveContainer>(this, (x) => x.User = User);
    }

在我的 AddressViewModel 中我也这样做。

    public AddressViewModel()
        : base(Messenger.Default)
    {
        Address = new Address();
        Address2 = new Address() { StreetName = "Washington Street" };

        MessengerInstance.Register<SaveContainer>(this, x =>
        {
            x.Address = Address;
            x.Address2 = Address2;
        });
    }

当我必须加载数据时,我也会这样做。


在我发送消息后,我假设每个注册的 ViewModel 都收到了消息并进行了处理。我假设错了吗?您认为这种方式是使用 Messenger 的正确方式吗?你会改进什么?

【问题讨论】:

    标签: c# wpf mvvm-light


    【解决方案1】:

    没有正确的方式来使用信使。但是,您必须考虑到该邮件是由 所有 已注册该邮件的收件人处理的,而不仅仅是一个预期的子集。此外,在使用消息传递时,您无法控制消息处理完成的时间,现在当所有收件人都完成处理消息时,您会收到通知。此外 - 根据信使的实现 - 消息可以并行处理。

    因此,您的方法(以及使用回调的@cadrell0 扩展)的问题在于您不知道所有收件人何时都处理了该消息。使用回调,您将获得处理消息的每个收件人的回调(即 n 个收件人 n 个回调)。

    那么,您如何检查所有收件人何时处理完邮件?

    • 您使用计数器来确定有多少收件人回电 - 这很容易出错,因为您可能会注册另一个消息收件人,这会扰乱您的系统。
    • 另一种方法是验证保存容器,一旦它完成继续处理 - 但这可能会导致竞争条件,因为您可能认为所有收件人都已处理该消息并继续,但随后一个迟到的收件人呼叫并使您的保存容器...不好。

    在我看来,消息传递更多地被设计为一种通知机制,即您通知某些收件人发生了某些事情。如果您知道并且可以确保只有一个收件人,您甚至可以按照您描述的方式使用它,但是一旦涉及多个收件人,就会导致上述问题。

    那么这会给你留下什么... /strong> 地址视图模型 - 或主视图模型了解用户视图模型,而用户视图模型又了解地址视图模型(如果这更合适)。通常,我还会设计一个模型来保存我必须处理的工作单元(在您的情况下是 SaveContainer)。然后所有的视图模型都是从这个模型构建的,并将它们的数据写入它。在正常情况下,这个工作单元是您从数据存储服务中获得的,而数据存储又在单个事务中保存了什么。

    但是,MVVM 没有正确的方法!

    【讨论】:

    • 我完全同意你所说的问题。我的带有回调的消息通常是“我需要完成一些工作,完成后告诉我。”
    【解决方案2】:

    如果在收件人回复消息后我需要做某事,我会在我的消息中包含回调。当接收者完成后,它会执行回调。向回调添加参数允许接收者向发送者发送数据。这也允许接收者执行异步操作。

    【讨论】:

    • 在这种特殊情况下,您将如何实现带有回调的消息?
    • 因为在这种情况下,我向多个recipents 发送消息,并且在所有这些recipents 都响应后我需要做一些事情,因为他们每个人都将一个对象放入容器中。不是在每次响应之后。
    • 我只发送从 Message 基类继承的数据。我有一个 MessageWithCallback 基类,它在构造函数中采用 Action 。如果您需要在 SaveContainer 可用之前对其执行多项操作,则回调需要检查对象,如果它尚未准备好,请不要采取行动。
    • @cadrell0 您提出的解决方案存在一些问题,请参阅我的回答了解我为什么这么认为。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-11
    • 2018-12-31
    • 2021-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多