如何动态绑定两个视图模型的公共属性?(MVVM, ViewModel-First )

本文关键字:属性 MVVM ViewModel-First 视图 动态绑定 两个 模型 | 更新日期: 2023-09-27 18:26:16

ViewModel1 通过导入包含数据值及其距离的.csv文件,从模型中动态获取数据源。ViewModel1 有两个参数化构造函数。它创建一个散点序列并将其存储在序列集合中。

private IEnumerable<Series> _myScatterSeries = new Collection<Series>(); 

View1 是使用 DataTemplates 创建的,以响应 ViewModel1。View1 绑定到 ViewModel1 的 MyScatterSeries 属性,并在散点图中显示序列表示形式。
视图1.xaml:

<Grid Loaded="Grid_Loaded">
   <ext:ChartExtension Style="{StaticResource ChartStyle1}" SeriesSource="{Binding MyScatterSeries}" />
</Grid>

我想创建一个新的视图窗口 (View2(,当我打开 View2 窗口时,它应该动态加载由 ViewModel1 创建的相同散点序列。我尝试在 View2 中使用相同的上述代码,但它只显示图表,但现在显示系列数据点。如何将视图模型 1 的 MyScatterSeries 属性动态绑定到 View2?

我不能使用以下,因为它的构造函数参数有问题。视图2.xaml-

<UserControl.DataContext>
    <vm:ViewModel1/>
</UserControl.DataContext>

我还尝试使用DataTemplate,添加堆栈面板并包装两个视图,但它不起作用。

由于它是ViewModel优先的方法,因此我为View2创建了一个新的ViewModel(ViewModel2(。但是我不知道如何使用代码将ViewModel1的MyScatterSeries绑定到ViewModel2。另外,我可以使用相同的视图 1 代码在视图 2 中显示散点序列吗?

如何动态绑定两个视图模型的公共属性?(MVVM, ViewModel-First )

我的第一个想法是拥有一个同时包含 ViewModel1 和 ViewModel2 的应用程序视图模型,并控制同步数据。

这是一个非常粗略的例子,应该给你一个大致的想法

public class ApplicationViewModel
{
    ViewModel1 ViewModel1 { get; set; }
    ViewModel2 ViewModel2 { get; set; }
    public ApplicationViewModel()
    {
        ViewModel1 = new ViewModel1(someParameters);
        ViewModel2 = new ViewModel2(otherParameters);
        ViewModel1.PropertyChanged += VM1_PropertyChanged;
    }
    private VM1_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "ScatterSeries")
            ViewModel2.ScatterSeries = ViewModel1.ScatterSeries;
    }    
}

如果需要,您也可以使用相同的技术让两个对象指向同一对象(不知道用户如何更新或维护此数据(

public class ApplicationViewModel
{
    ViewModel1 ViewModel1 { get; set; }
    ViewModel2 ViewModel2 { get; set; }
    private IEnumerable<Series> _myScatterSeries;
    public ApplicationViewModel()
    {
        _myScatterSeries = new Collection<Series>(); 
        ViewModel1 = new ViewModel1(someParameters, _myScatterSeries);
        ViewModel2 = new ViewModel2(otherParameters, _myScatterSeries);
    }   
}

另一种选择是在 VM1 数据更改时使用某种消息传递系统广播消息,VM2 将订阅这些消息并控制同步数据。这是一个很大的主题,但如果你有兴趣,我可以在我的博客上快速概述ViewModels与MVVM之间的通信

最后,您可以确保 View1 和 View2 都将其 DataContext 设置为 ViewModel1,前提是没有其他差异。例如

<DataTemplate x:Key="View1"> 
    <vw:View1/> 
</DataTemplate> 
<DataTemplate x:Key="View2"> 
    <vw:View2 /> 
</DataTemplate>
...
<ContentControl Content="{Binding ViewModel1}" ContentTemplate="{StaticResource View1}" />
<ContentControl Content="{Binding ViewModel1}" ContentTemplate="{StaticResource View2}" />

我没有看到您的.DataContext如何在上面的代码中设置,因此无法为此提供任何相关的代码示例,但这始终是一种选择。

可以在构造函数中以编程方式设置 View 的 DataContext,如下所示:

//Constructor
public View2()
{
   InitializeComponent();
   DataContext = new ExampleViewModel();
}

您可以将要创建的视图模型传递给构造函数,或存储包含视图模型的全局变量。