【问题标题】:How should I communicate between ViewModels?我应该如何在 ViewModel 之间进行通信?
【发布时间】:2013-10-02 12:19:53
【问题描述】:

我正在使用 MVVM Light 并使用打包的 messenger 系统在视图模型之间进行通信,但是我遇到了一些难题!基本上,当用户单击客户记录时,会打开相应的视图并实例化 CustomerViewModel。此时,CustomerViewModel 需要从前一个视图模型 (ViewAllCustomersViewModel) 中选择的客户 ID,以便它可以获取视图绑定到的选定客户信息(仍在关注?) .所以最初我的想法是在 ViewAllCustomersViewModel(选择要查看的客户的位置)的消息中将该 ID 发送到 CustomerViewModel...但是,CustomerViewModel 直到视图加载(此时消息已经被广播)才被实例化以便能够接收消息!

那么,解决这个问题的最佳方法是什么?到目前为止,我已经考虑了 CustomerViewModel 在实例化后向 ViewAllCustomersViewModel 发送请求(基本上是说“我准备好接收消息”),然后 em>ViewAllCustomersViewModel 将 ID 发送回 CustomerViewModel...但这是解决此问题的必要方法吗?我觉得有点丑!

否则,我在想是否有另一种沟通方式可以解决我遇到的问题?但是,这难道不是消息系统的全部意义……能够在视图模型之间进行通信吗?或者我可以强制在启动时实例化视图模型吗?如果是这样,这将如何影响 ViewModelLocator

我希望我已经清楚地概述了这个问题,我使用了虚构的视图模型名称来进行解释......请随时编辑或建议您希望我添加的任何其他信息!

【问题讨论】:

  • @Sam 先生,我觉得你的问题非常合适:D

标签: c# wpf mvvm viewmodel mvvm-light


【解决方案1】:

您是否尝试通过您的模型进行交流?直到最后我都无法阅读您的主题,但这就是我在 ViewModel 之间进行通信的方式。 两个视图模型都有会话实例。

public ViewModel1(ISession session)
        {
            _session = session;           
        }

public ViewModel2(ISession session)
        {
            _session = session;           
        }

这样,当您在 BDD(行为驱动开发)中测试您的应用程序时,您可以在没有视图的情况下测试您的应用程序。胶水就是模型。

正如您在这张图片上看到的,您应该能够在没有视图的情况下测试您的应用程序。

【讨论】:

  • 这张图片来自哪里?那是一本书还是关于应用程序结构的东西?
【解决方案2】:

我遇到了两个视图模型相互通信的相同情况。我使用 Microsoft PRISM 框架发布和订阅。

在您的情况下,CustomerViewModel 是父视图,而 ViewAllCustomersViewModel 是子视图。

  1. https://www.nuget.org/packages/Prism.PubSubEvents/下载prism框架“Microsoft.Practices.Prism.PubSubEvents.dll”

  2. 将 prism 引用添加到您的项目“Microsoft.Practices.Prism.PubSubEvents.dll”

  3. 创建一些用于通信调制解调器的自定义类。

      class Notifications : PubSubEvent<string>
      {
    
      }
    
  4. 为你的项目创建IEventAggregator eventAggregator单例实例并初始化它。

      public sealed class SessionInfo
      {
            public  IEventAggregator eventHanlder;
    
            private SessionInfo (){
    
            }
    
            private static SessionInfo _instance = null;
    
            public static SessionInfo Instance{
                    get{
                     lock (lockObj){
                      if (_instance == null) {
                        _instance = new SessionInfo ();
                        _instance.eventHanlder= new EventAggregator();
                       }
                   }
                      return _instance;
                   }
                 }
                }
    
  5. 进入Popover模型(ViewAllCustomersViwModel)按钮事件处理及下面代码。现已发布。

ViewAllCustomersViwModel.cs:

      public void OnSelectedItem(Item item)
     {
            SessionInfo.Instance.eventHanlder.GetEvent<Notification>().Publish(item.id);

      }
  1. 必须在需要的地方订阅这些事件聚合器。因此,在您的父视图模型 (CustomerViewModel) 上添加以下代码

CustomerViewModel.cs

       public class CustomerViewModel
      {
               public CustomerViewModel()
              {
                  SessionInfo.Instance.eventHanlder.GetEvent<Notifications>().Subscribe(OnReceivedNotification);

               }

        //Handling the notification 
    public void OnReceivedNotification(string itemId)
        {
            Debug.WriteLine("Item Id is :" + itemId);

        }


     }

更多信息:

https://sites.google.com/site/greateindiaclub/mobil-apps/windows8/communicationbetweenviewmodelsinwindows8mvvmpattern

【讨论】:

  • 如果我要从许多 ViewModel 发布许多事件怎么办?如何使 ViewModel1 的 event1 仅针对 ViewModel2?
【解决方案3】:

我相信标准方法是通过 View 传递它。 根据您实例化视图的方式,它可能是 DependencyProperty 绑定到 XAML、构造函数参数或其他任何内容。 然后 View 将其传递给它的 ViewModel(将其推送到 VM,而不是反过来:ViewModel 不应该知道 View)。这样你就得到了一个独立的封闭组件(你的视图),而外部代码不知道它的内部实现(即 ViewModel)。

在 XAML 中它可能类似于

<ListBox x:Name="customers" />
<CustomerView Customer="{Binding SelectedItem, ElementName=customers}" />

然后在 CustomerPropertyChanged 处理程序中将值推送到 ViewModel。

【讨论】:

    【解决方案4】:

    就我个人而言,我曾经使用过 MVVM-Light Messenger,但发现我可以让很多消息四处飞散,我不喜欢使用“神奇”的 Messenger 的感觉。我所做的概述为以下链接的答案

    Best Way to Pass Data to new ViewModel when it is initiated.

    现在我警告你,我回答了我自己的问题,没有人验证它是好是坏,但它适用于我的情况,并且消除了对 MVVM-Light Messenger 的需求。因为我的程序在我的实现中使用了多个线程,所以我将存储库中的所有条目都更改为以 CurrentThread.ManagedThreadId 作为键的字典。

    【讨论】:

      【解决方案5】:

      到目前为止,我已经考虑了 CustomerViewModel 向 ViewAllCustomersViewModel 一旦被实例化(基本上 说“我准备好接收消息”),然后 ViewAllCustomersViewModel 将 ID 发送回 客户视图模型...

      我会继续这个想法。与其他答案不同,它使 Views、ViewModels 和 Models 都是分开的,并且不知道其他人。并不是说其他​​答案是错误的,甚至是不好的,您的选择可以定义为以下之一或任何一个:个人偏好、团队约定、替换组件/模块的长期 MVVM 目标以及编码的复杂性/易用性。

      我在上面引用的您的想法的一个副作用是,您可以随时请求,因为您已经设置了它。因此,如果您更改 when 以非常轻松地执行该请求,或者如果您需要请求 更新,您可以使用相同的通信架构。

      最后,我更喜欢它,因为如果您更改模型或视图或视图模型 - 您将保持组件之间通信信息的相同核心概念。

      【讨论】:

      • 我完全同意你所说的,但是,我确实认为必须有一个更简洁的解决方案来提供所有选项中最好的!与此同时,我只是在广播消息之前检查了 View 模型是否已实例化!此检查在视图模型的构造函数中执行,因此检查只发生一次!实际上意味着任何视图模型都会触发它们可以向其广播消息的所有视图模型的实例化!不是我知道的最好的解决方案!不过,我将来会重新考虑这个解决方案!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-18
      • 2014-02-19
      • 1970-01-01
      相关资源
      最近更新 更多