简体   繁体   English

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

[英]How should I communicate between ViewModels?

I am using MVVM Light and have used the packaged messenger system to communicate between view models, however I have hit a bit of a dilemma! 我正在使用MVVM Light,并使用打包的messenger系统在视图模型之间进行通信,但是我遇到了一些两难的问题! Basically when a user clicks on a customer record the corresponding view is opened and with it the CustomerViewModel is instantiated. 基本上,当用户单击客户记录时,将打开相应的视图,并使用它来实例化CustomerViewModel At this point the CustomerViewModel requires the selected customers ID from the previous view model ( ViewAllCustomersViewModel ) so that it can get selected customers info which the view binds to (still following?). 此时, CustomerViewModel需要来自先前视图模型( ViewAllCustomersViewModel )的所选客户ID,以便它可以获取视图所绑定的选定客户信息(仍然跟随?)。 So initially my thought was too send that ID in a message from the ViewAllCustomersViewModel (where the customer to be viewed is selected) to the CustomerViewModel ... HOWEVER, the CustomerViewModel is not instantiated to be able to receive the message until the view is loaded (at which point the message has already been broadcast)! 所以最初我的想法是将来自ViewAllCustomersViewModel (选择要查看的客户)的消息中的ID发送到CustomerViewModel ...但是, CustomerViewModel未实例化以便能够在加载视图之前接收消息(此时消息已经播出)!

So, what would be the best way to solve this issue? 那么,解决这个问题的最佳方法是什么? So far I have considered the CustomerViewModel sending a request to the ViewAllCustomersViewModel once it has been instantiated (basically saying "I am ready to receive the message"), and then the ViewAllCustomersViewModel sending the ID back to the CustomerViewModel ... but is this a necessary approach to solve this? 到目前为止,我已经考虑过CustomerViewModel在实例化后向ViewAllCustomersViewModel发送请求(基本上说“我准备接收消息”),然后ViewAllCustomersViewModel将ID发送回CustomerViewModel ......但这是一个解决这个问题的必要方法? It seems a bit ugly to me! 这对我来说似乎有点难看!

Otherwise, I was thinking is there another way to communicate which can account for the issue I am having? 否则,我在想是否有另一种沟通方式可以解释我遇到的问题? But then isn't this the whole point of the messaging system... to be able to communicate between view models? 但是,这不是消息系统的全部意义......能够在视图模型之间进行通信吗? OR can I force the view model to be instantiated on start up? 或者我可以强制在启动时实例化视图模型吗? If so, how would that affect the ViewModelLocator ? 如果是这样,那将如何影响ViewModelLocator

I hope I have outlined the issue clearly, I have used fictional view model names for the purpose of the explanation... and please feel free to edit or suggest any additional information that you would like me to add! 我希望我已经清楚地概述了这个问题,为了解释的目的,我使用了虚构的视图模型名称...请随时编辑或建议您希望我添加的任何其他信息!

Did you try to communicate via your model? 您是否尝试通过您的模型进行交流? I was not able to read your topic until the end but this is how I communicate between ViewModels. 直到最后我才能阅读您的主题,但这是我在ViewModels之间进行通信的方式。 Both View Models have the instance of session. 两个View Models都具有会话实例。

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

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

This way, when you test your application in BDD (behavior driven development), you can test your application without the view. 这样,当您在BDD(行为驱动开发)中测试应用程序时,您可以在没有视图的情况下测试应用程序。 The glue is the model. 胶水是模型。

As you can see on this picture, you should be able to test your application without the view. 正如您在此图片中看到的那样,您应该能够在没有视图的情况下测试您的应用程序。 在此输入图像描述

I came across the same situation where two view model is communicating each other. 我遇到了两种视图模型相互通信的情况。 I have used Microsoft PRISM framework to publish and Subscribe. 我使用Microsoft PRISM框架发布和订阅。

In your case CustomerViewModel is parent View and ViewAllCustomersViewModel is child view. 在您的情况下,CustomerViewModel是父View,ViewAllCustomersViewModel是子视图。

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

  2. Add prism reference to your project "Microsoft.Practices.Prism.PubSubEvents.dll" 为项目“Microsoft.Practices.Prism.PubSubEvents.dll”添加prism引用

  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. 为项目创建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. Go to Popover model (ViewAllCustomersViwModel) button events handling and below codes in it.Now it has been published. 转到Popover模型(ViewAllCustomersViwModel)按钮事件处理及其下面的代码。现在它已经发布。

In ViewAllCustomersViwModel.cs : ViewAllCustomersViwModel.cs

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

      }
  1. These event aggregator has to be subscribe where it is needed. 这些事件聚合器必须在需要的地方进行订阅。 So add below code on your Parent View model (CustomerViewModel) 因此,在您的父视图模型(CustomerViewModel)上添加以下代码

CustomerViewModel.cs 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);

        }


     }

For more information: 欲获得更多信息:

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

I believe that standard way is to pass it through View. 我相信标准的方法是通过View传递它。 Depending on how you instantiate your views, it could be DependencyProperty to bind in XAML, constructor parameter, or anything else. 根据您实例化视图的方式,可能是要在XAML,构造函数参数或其他任何内容中绑定的DependencyProperty。 Then View passes it to it's ViewModel (pushes it to VM, not the way around: ViewModel should not be aware of View). 然后View将它传递给它的ViewModel(将其推送到VM,而不是解决方法:ViewModel不应该知道View)。 This way you get a standalone closed component (your View), and external code does not know about it's internal implementation (which is ViewModel). 这样您就可以得到一个独立的封闭组件(您的视图),而外部代码不知道它的内部实现(即ViewModel)。

In XAML it can be something like 在XAML中它可以是类似的东西

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

And then in CustomerPropertyChanged handler you push value to the ViewModel. 然后在CustomerPropertyChanged处理程序中将值推送到ViewModel。

Personally, I used to use the MVVM-Light Messenger, but found I had way to many messages flying around, and I didn't like the feeling of using a "magical" messenger. 就个人而言,我曾经使用MVVM-Light Messenger,但发现我有很多信息飞来飞去,我不喜欢使用“神奇”信使的感觉。 What I did is outlined as the answer to the following link 我所做的是概述为以下链接的答案

Best Way to Pass Data to new ViewModel when it is initiated . 启动时将数据传递给新ViewModel的最佳方法

Now I warn you, I answered my own question, and nobody verfied it as good or bad practice, however it works for my situation and has elimnated the need for MVVM-Light Messenger. 现在我警告你,我回答了我自己的问题,并没有人将其视为好的或坏的做法,但它适用于我的情况并且已经消除了对MVVM-Light Messenger的需求。 Because my program uses multiple threads in my implementation I changed all the entries in the repository to Dictionarys with the CurrentThread.ManagedThreadId as the Key. 因为我的程序在我的实现中使用多个线程,所以我将存储库中的所有条目更改为Dictionarys,并将CurrentThread.ManagedThreadId作为Key。

So far I have considered the CustomerViewModel sending a request to the ViewAllCustomersViewModel once it has been instantiated (basically saying "I am ready to receive the message"), and then the ViewAllCustomersViewModel sending the ID back to the CustomerViewModel... 到目前为止,我已经考虑过CustomerViewModel在实例化后向ViewAllCustomersViewModel发送请求(基本上说“我准备接收消息”),然后ViewAllCustomersViewModel将ID发送回CustomerViewModel ...

I would continue with this idea. 我会继续这个想法。 It keeps the Views, ViewModels and Models all separate and unknowing of the others unlike other answers. 与其他答案不同,它使Views,ViewModel和Models保持独立且不知道其他人。 Not to say other answers are wrong, or even bad, your option can be defined one or any of: personal preference, team convention, long-term MVVM goal of replacing components/modules, and complexity/ease of coding. 不是说其他​​答案是错误的,甚至是坏的,您的选项可以定义为以下一个或任何一个:个人偏好,团队惯例,替换组件/模块的长期MVVM目标,以及编码的复杂性/易用性。

A side-effect to your idea I quoted above, which I prefer, is that you can request at any time as you've already set it up. 我上面引用的一个副作用,我更喜欢的是,您可以随时请求,因为您已经设置了它。 So if you change when to perform that request very easily, or if you need to request updates , you use the same communication architecture in place. 因此,如果您更改何时非常轻松地执行该请求,或者您需要请求更新 ,则可以使用相同的通信体系结构。

Lastly, I prefer it because if you change your models or views or viewmodels - you keep the same core concept of communicating information between components. 最后,我更喜欢它,因为如果您更改模型或视图或视图模型 - 您保持在组件之间传递信息的相同核心概念。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM