C# ViewModels在没有框架的情况下相互通信
导言 我有一个在运行时导入实验室仪器数据的应用程序。该数据被导入,然后以最终用户根据其测试要求设置的间隔显示在C# ViewModels在没有框架的情况下相互通信,c#,wpf,mvvm,C#,Wpf,Mvvm,导言 我有一个在运行时导入实验室仪器数据的应用程序。该数据被导入,然后以最终用户根据其测试要求设置的间隔显示在列表视图中。当感兴趣的值出现在他们观察的列表视图中时,他们按下开始按钮,应用程序开始对该数据和后续数据执行计算,直到按下停止按钮。因此,屏幕左侧是一个用于显示导入数据的视图,右侧是另一个用于在计算和显示值和统计数据时查看它们的视图 当前代码 显示导入数据的ListView的视图是ImportProcessView.xaml,它将其DataContext设置为ImportProcessVi
列表视图中。当感兴趣的值出现在他们观察的列表视图中时,他们按下开始按钮,应用程序开始对该数据和后续数据执行计算,直到按下停止按钮。因此,屏幕左侧是一个用于显示导入数据的视图,右侧是另一个用于在计算和显示值和统计数据时查看它们的视图
当前代码
显示导入数据的ListView的视图是ImportProcessView.xaml,它将其DataContext
设置为ImportProcessViewModel.cs
。我刚才介绍的VM有一个属性observecteCollection
,我刚才也描述了ListView绑定到该属性。现在来看有趣的部分
ImportProcessView
有一个ContentControl
,它动态地将其内容设置为一个UserControl,表示特定于最终用户选择的阶段类型的控件和字段
<StackPanel Background="White" Margin="5">
<ContentControl Content="{Binding CurrentPhaseView}"/>
</StackPanel>
有三个PhaseViews
,每个都在自己的用户控件中,每个都将其DataContext
设置为ImportProcessViewModel
。因此,我得到一些严重的虚拟机膨胀到2000行左右。荒唐的我知道。膨胀的原因是,importProcessViewModel
通过三个PhaseView中每个的属性来维护状态,不仅如此,还包含用于执行计算的方法,其数据存储和显示在这些“PhaseView”中
我正在努力实现的目标
显然,在ImportProcessViewModel
变得更加笨拙之前,我需要将其分解,以便每个PhaseView都有自己的ViewModel,但为了IrData
的ObservableCollection所施加的依赖性,每个ViewModel都要维护回ImportProcessViewModel的关系
研发
我已经研究了ViewModels之间的通信,但大多数都涉及使用特定MVVM框架编写的应用程序。我没有使用框架,在项目的这一点上,重构它开始使用框架已经太晚了
然而,我确实发现了这一点,而“hbarck”提供的答案表明,要实现我想要的结果,需要一些简单的组合,但由于我对数据模板没有太多经验,我不理解他/她建议公开的意思UserControl的ViewModel作为主ViewModel上的属性,并将ContentControl绑定到此属性,然后该属性将通过DataTemplate实例化视图(即UserControl)
具体来说,我不理解“将ContentControl绑定到此属性,然后通过DataTemplate实例化视图”是什么意思
有人可以通过一个代码示例来澄清在这个示例的上下文中通过DataTemplate实例化视图是什么意思吗
此外,这是一种好方法(如“hbarck”所建议的那样)吗
正如大家所看到的,我已经将ContentControl的Content属性设置为要实例化的阶段视图。我只是不知道涉及DataTemplate会是什么样子
我不明白他/她建议揭露“真相”是什么意思
UserControl的ViewModel作为主ViewModel上的属性,并绑定
此属性的ContentControl,然后它将实例化
通过数据模板查看(即UserControl)
DataTemplate
允许您指定视图(如用户控件)和视图模型之间的关系
<DataTemplate DataType="{x:Type myApp:MyViewModel}">
<myApp:MyUserControl />
</DataTemplate>
如果您有一个指定ChildViewModel
和用户控件之间关系的DataTemplate
,WPF将自动将用户控件加载到视图中
我提供的另一个问题也可能为您提供一些帮助
我需要将其分解,以便每个PhaseView都有自己的ViewModel,
但也要确保每个ViewModel都保持与
ImportProcessViewModel
这将允许您将viewModels拆分为更小、更易于管理的viewModels,这些viewModels可以自行管理。这将给您带来viewModels之间的通信问题
如果按照建议嵌套viewModels,则子viewModels可能会公开父viewModel可以绑定到的事件,以便在发生更改时收到通知。类似如下:
public class ParentViewModel // Derive from some viewModel base that implements INPC
{
public ParentViewModel()
{
childViewModel = new ChildViewModel();
childViewModel.SomeEvent += someEventHandler;
// Don't forget to un-subscribe from the event at some point...
}
private void SomeEventHandler(object sender, MyArgs args)
{
// Update your calculations from here...
}
}
<DataTemplate DataType="{x:Type my:Phase1VM}">
<my:Phase1View/>
</DataTemplate>
<DataTemplate DataType="{x:Type my:Phase2VM}">
<my:Phase2View/>
</DataTemplate>
<DataTemplate DataType="{x:Type my:Phase3VM}">
<my:Phase3View/>
</DataTemplate>
<ContentControl Content="{Binding CurrentPhaseVM}"/>
这很简单,不需要任何额外的框架。有些人可能会反对这种方法,但它是一种有效的解决方案。缺点是viewModels必须知道彼此的存在,才能订阅事件,因此最终可能会紧密耦合。您可以使用标准的面向对象设计原则不过要绕开这一点(即,从接口派生子视图模型,以便父视图只知道接口而不知道实现)
如果你真的想进行松散耦合的通信,那么你需要使用某种类型的事件聚合或消息总线系统。这与上述方法类似,只是有一个对象位于视图模型之间,充当中介,这样视图模型就不必知道彼此的存在。My提供了更多的信息
有现成的解决方案可供使用,但这需要采用额外的框架。我建议使用,因为它非常简单,而且您只需要使用单个类。
<ContentControl Content="{Binding CurrentPhaseVM}"/>