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

时间:2015-12-09 14:11:00

标签: c# wpf mvvm data-binding

ViewModel1通过导入包含数据值及其距离的.csv文件,从Model动态获取数据源。 ViewModel1有两个参数化构造函数。它会创建一个散布系列并将其存储在Series Collection中。

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

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

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

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

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

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

我也尝试过使用DataTemplate,添加堆栈面板并包装两个视图,但它无法正常工作。

由于它是ViewModel-First方法,我为View2创建了一个新的ViewModel(ViewModel2)。但我不知道如何使用代码将MyScatterSeries的ViewModel1绑定到ViewModel2。 另外,我可以使用相同的View1代码在View2中显示分散系列吗?

2 个答案:

答案 0 :(得分:3)

我的第一个想法是拥有一个包含ViewModel1和ViewModel2的ApplicationViewModel,并控制同步数据。

这是一个非常粗略的例子,可以给你一般的想法

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会订阅这些消息并控制同步数据。这是一个很重要的主题,但如果您有兴趣,我可以在我的博客Communication between ViewModels with 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是如何设置的,所以不能为此提供任何相关的代码示例,但它始终是一个选项。

答案 1 :(得分:0)

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

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

您可以将要创建的ViewModel传递给构造函数,或者存储包​​含ViewModel的全局变量。