我应该如何在ViewModels之间进行通信?

时间:2013-09-26 13:33:47

标签: c# wpf mvvm viewmodel mvvm-light

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

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

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

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

5 个答案:

答案 0 :(得分:5)

您是否尝试通过您的模型进行交流?直到最后我才能阅读您的主题,但这是我在ViewModels之间进行通信的方式。 两个View Models都有会话实例。

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

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

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

正如您在此图片中看到的那样,您应该能够在没有视图的情况下测试您的应用程序。 enter image description here

答案 1 :(得分:3)

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

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

  1. 下载prism framework&#34; Microsoft.Practices.Prism.PubSubEvents.dll&#34;来自https://www.nuget.org/packages/Prism.PubSubEvents/

  2. 为您的项目添加prism引用&#34; Microsoft.Practices.Prism.PubSubEvents.dll&#34;

  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)按钮事件处理及其下面的代码。现在它已经发布。

  6. ViewAllCustomersViwModel.cs

          public void OnSelectedItem(Item item)
         {
                SessionInfo.Instance.eventHanlder.GetEvent<Notification>().Publish(item.id);
    
          }
    
    1. 这些事件聚合器必须在需要的地方进行订阅。因此,在您的父视图模型(CustomerViewModel)上添加以下代码
    2. 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

答案 2 :(得分:2)

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

在XAML中它可以是

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

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

答案 3 :(得分:2)

就个人而言,我曾经使用MVVM-Light Messenger,但发现我有很多信息飞来飞去,我不喜欢使用“魔法”信使的感觉。我所做的是概述为以下链接的答案

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

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

答案 4 :(得分:1)

  

到目前为止,我已经考虑过向CustomerViewModel发送请求   ViewAllCustomersViewModel一旦被实例化(基本上   说“我准备收到消息”),然后是   ViewAllCustomersViewModel将ID发回给   CustomerViewModel ...

我会继续这个想法。与其他答案不同,它使Views,ViewModel和Models保持独立且不知道其他人。不是说其他​​答案是错误的,甚至是坏的,你的选择可以定义为以下一个或任何一个:个人偏好,团队惯例,替换组件/模块的长期MVVM目标,以及编码的复杂性/易用性。

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

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