如何在ViewModel之间进行通信?

7
我正在使用MVVM Light,并已经使用打包的信使系统在视图模型之间进行通信,但是我遇到了一个问题!基本上,当用户单击客户记录时,相应的视图将被打开,并且CustomerViewModel也将被实例化。此时,CustomerViewModel需要来自前一个视图模型(ViewAllCustomersViewModel)的选定客户ID,以便可以获取所选客户信息,这些信息由视图绑定(还在跟进吗?)。因此,最初我的想法是从ViewAllCustomersViewModel(选择要查看的客户所在的位置)向CustomerViewModel发送一条消息,其中包含该ID... 但是,CustomerViewModel未被实例化,无法接收消息,直到视图加载(此时消息已经被广播)!
那么,解决这个问题的最佳方法是什么?到目前为止,我考虑过CustomerViewModel一旦被实例化就向ViewAllCustomersViewModel发送请求(基本上是说“我准备好接收消息了”),然后ViewAllCustomersViewModel将ID返回给CustomerViewModel... 但是,这是解决这个问题的必要方法吗?对我来说,这似乎有点丑陋!
否则,我在想是否有另一种通信方式可以解决我遇到的问题?但这不是消息系统的整个目的吗...能够在视图模型之间进行通信吗?或者我可以强制启动视图模型吗?如果可以,那么这将如何影响ViewModelLocator
希望我已经清楚地概述了问题,我已经使用虚构的视图模型名称来说明...请随意编辑或建议您想要添加的任何其他信息!

先生@Sam,我认为您的问题非常合适:D - Sonny D
5个回答

7

你是否尝试通过你的模型进行通信?我没有能够完全阅读你的话题,但这是我在ViewModel之间进行通信的方式。两个ViewModel都有session的实例。

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

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

这样,在进行BDD (行为驱动开发)测试时,您可以在没有视图的情况下测试应用程序。模型是粘合剂。
如您在此图片中所看到的,您应该能够在没有视图的情况下测试您的应用程序。 enter image description here

1
这张图片是从哪里来的?是一本书还是关于应用程序结构的内容? - KulaGGin

4
我遇到了两个视图模型相互通信的情况。我使用了微软PRISM框架进行发布和订阅。
在您的情况下,CustomerViewModel是父视图,ViewAllCustomersViewModel是子视图。
  1. Download prism framework "Microsoft.Practices.Prism.PubSubEvents.dll" from https://www.nuget.org/packages/Prism.PubSubEvents/

  2. Add prism reference to your project "Microsoft.Practices.Prism.PubSubEvents.dll"

  3. Create some custom class which is used for communication modem.

      class Notifications : PubSubEvent<string>
      {
    
      }
    
  4. Create IEventAggregator eventAggregator singleton instance for your project and initialize it.

      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. Go to Popover model (ViewAllCustomersViwModel) button events handling and below codes in it.Now it has been published.

在ViewAllCustomersViewModel.cs中:
      public void OnSelectedItem(Item item)
     {
            SessionInfo.Instance.eventHanlder.GetEvent<Notification>().Publish(item.id);

      }

这个事件聚合器必须在需要的地方进行订阅。因此,请在您的父视图模型(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的事件1仅针对ViewModel2? - YukiSakura

2
我相信标准的方法是通过View传递。 根据您如何实例化视图,它可以是在XAML中绑定的DependencyProperty、构造函数参数或其他任何内容。 然后View将其传递给其ViewModel(将其推送到VM,而不是反过来:ViewModel不应该知道View)。这样,您就可以获得一个独立的封闭组件(您的View),外部代码不知道其内部实现(即ViewModel)。
在XAML中,可以像这样:
<ListBox x:Name="customers" />
<CustomerView Customer="{Binding SelectedItem, ElementName=customers}" />

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


2
个人而言,我曾经使用MVVM-Light Messenger,但发现我的消息太多了,而且我不喜欢使用“神奇”的信使。我所做的事情在以下链接的答案中概述:Best Way to Pass Data to new ViewModel when it is initiated
现在我要警告你,我回答了自己的问题,没有人验证过它是好还是坏的做法,但它适用于我的情况,并且消除了对MVVM-Light Messenger的需求。由于我的程序在实现中使用多个线程,因此我将存储库中的所有条目更改为带有CurrentThread.ManagedThreadId作为键的字典。

1
到目前为止,我考虑过一旦 CustomerViewModel 被实例化(基本上是说“我准备好接收消息了”),它会向 ViewAllCustomersViewModel 发送请求,然后 ViewAllCustomersViewModel 将 ID 发送回 CustomerViewModel... 我会继续这个想法。它保持了视图、视图模型和模型的分离,并使它们互相不知道,与其他答案不同。并不是说其他答案是错的,甚至是不好的,你的选择可以被定义为以下之一:个人偏好、团队约定、长期 MVVM 目标替换组件/模块,以及编码的复杂性/易用性。你引用的这个想法的一个副作用,我更喜欢的是,你可以随时请求,因为你已经设置好了。所以如果你很容易改变请求的时间,或者如果你需要请求更新,你可以使用同样的通信架构。最后,我更喜欢它,因为如果你改变了你的模型或视图或视图模型——你仍然保持了在组件之间传递信息的核心概念。

我完全同意你所说的,但是我觉得必须有一个更简洁的解决方案,以提供所有选项的最佳选择!同时,我已经采用了简单地检查视图模型是否已被实例化,然后再广播消息的方法!这个检查在视图模型的构造函数中执行,因此检查只会发生一次!有效地意味着任何视图模型都将触发所有可以广播消息的视图模型的实例化!虽然不是最好的解决方案,但我将来会重新设计这个解决方案! - Sam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接