我正在使用MVVM Light并使用打包的信使系统在视图模型之间进行通信,但是我遇到了一些两难的困境!基本上,当用户单击客户记录时,将打开相应的视图,并通过它实例化 CustomerViewModel 。此时, CustomerViewModel 需要先前视图模型中选定的客户ID( ViewAllCustomersViewModel ),以便它可以获取视图所绑定的选定客户信息(仍在关注?) 。所以最初我的想法是将 ViewAllCustomersViewModel (要选择的客户被选中)的消息中的ID发送到 CustomerViewModel ...但是, > CustomerViewModel 未实例化,以便在加载视图之前能够接收消息(此时消息已被广播)!
那么,解决这个问题的最佳方法是什么?到目前为止,我已经考虑过 CustomerViewModel 在实例化后向 ViewAllCustomersViewModel 发送请求(基本上说“我准备接收消息”),然后< em> ViewAllCustomersViewModel 将ID发送回 CustomerViewModel ...但这是解决此问题的必要方法吗?对我来说似乎有点难看!
否则,我在想是否有另一种沟通方式可以解释我遇到的问题?但是,这不是消息系统的全部意义......能够在视图模型之间进行通信吗?或者我可以强制在启动时实例化视图模型吗?如果是这样,那将如何影响 ViewModelLocator ?
我希望我已经清楚地概述了这个问题,为了解释的目的,我使用了虚构的视图模型名称......请随时编辑或建议您希望我添加的任何其他信息!
答案 0 :(得分:5)
您是否尝试通过您的模型进行交流?直到最后我才能阅读您的主题,但这是我在ViewModels之间进行通信的方式。 两个View Models都有会话实例。
public ViewModel1(ISession session)
{
_session = session;
}
public ViewModel2(ISession session)
{
_session = session;
}
这样,当您在BDD(行为驱动开发)中测试应用程序时,您可以在没有视图的情况下测试应用程序。胶水是模型。
正如您在此图片中看到的那样,您应该能够在没有视图的情况下测试您的应用程序。
答案 1 :(得分:3)
我遇到了两种视图模型相互通信的情况。我使用Microsoft PRISM框架发布和订阅。
在您的情况下,CustomerViewModel是父View,ViewAllCustomersViewModel是子视图。
下载prism framework&#34; Microsoft.Practices.Prism.PubSubEvents.dll&#34;来自https://www.nuget.org/packages/Prism.PubSubEvents/
为您的项目添加prism引用&#34; Microsoft.Practices.Prism.PubSubEvents.dll&#34;
创建一些用于通信调制解调器的自定义类。
class Notifications : PubSubEvent<string>
{
}
为您的项目创建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;
}
}
}
转到Popover模型(ViewAllCustomersViwModel)按钮事件处理及其下面的代码。现在它已经发布。
在ViewAllCustomersViwModel.cs
:
public void OnSelectedItem(Item item)
{
SessionInfo.Instance.eventHanlder.GetEvent<Notification>().Publish(item.id);
}
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);
}
}
了解更多信息:
答案 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目标,以及编码的复杂性/易用性。
我上面引用的您的想法的副作用,我更喜欢,是您可以随时请求,因为您已经设置了它。因此,如果您在时更改以非常轻松地执行该请求,或者您需要请求更新,则可以使用相同的通信架构。
最后,我更喜欢它,因为如果您更改模型或视图或视图模型 - 您保持在组件之间传递信息的核心概念。