WPF MVVM将集合绑定到DataTemplate

时间:2018-04-06 15:39:06

标签: c# wpf mvvm binding observablecollection

我有一个ViewModel,其ObservableCollection<MyData> MainCollectionMyData SelectedData保存MainCollection中当前选定的项目。 MyData由多个属性和ObservableCollection<MyValuePair> MyPairs组成。 MyValuePair由2个属性DescriptionValue组成,就像KeyValuePair一样(不能使用字典,因为我想要使用TwoWay绑定)。

我希望根据我的DataTemplate动态创建foreach MyValuePair的控件(我试着像这里一样:Adding controls dynamically in WPF MVVM):

        //do not want to create another viewModel
        <DataTemplate DataType="{x:Type vm:MyValuePairViewModel }">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>

            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            //problem can only select one MyValuePair at a time
            <TextBlock Text="{Binding MyValuePair.Description, Mode=TwoWay}"/>
            <TextBox Template="{StaticResource TextBoxBaseControlTemplate}" Grid.Row="0" Grid.Column="1" Text="{Binding MyValuePair.Value, Mode=TwoWay}"/>
        </Grid>
    </DataTemplate>

迈德特:

public class MyData
{
    //Properties
    ObservableCollection<MyValuePair> MyPairs { get; set; }
}

MainViewModel:

public class MainViewModel : ViewModelBase
{
    ObservableCollection<MyData> MainCollection { get; set; }

    MyData selectedData
    public MyData SelectedData
    {
        get { return selectedData; }
        set
        {
            Set(() => SelectedData, ref selectedData, value);
        }
    }
}

MyValuePair:

public class MyValuePair
{
    private string description;
    public string Description
    {
        get { return description; }
        set { description = value; }
    }

    private string _value;
    public string Value
    {
        get { return _value; }
        set { _value = value; }
    }

但问题是我不想为我的MyValuePair创建另一个ViewModel(MyValuePairViewModel),因为每次SelectedData更改或MyPair(MyValuePair类型)更改时我都必须将其与MainViewModel同步必须将它同步回MainViewModel并且感觉不对。

那么有一种简单的方法可以将我的DataTemplate直接绑定到SelectedData中ObservableCollection<MyValuePair>属性中的每个元素,以便为每个MyPairs创建DataTemplate吗?

修改 目前我正在使用另一个ViewModel:

public class MyValuePairViewModel : ViewModelBase
{
    private MyValuePair myValuePair;
    public MyValuePair MyValuePair
    {
        get { return myPair; }
        set
        {
            Set(() => MyValuePair, ref myValuePair, value);
        }
    }

    public MyValuePairViewModel(MyValuePair myValuePair)
    {
        MyValuePair = myValuePair;
    }
}

并将其添加到我的MainViewModel中,如下所示:
public ObservableCollection<MyValuePairViewModel> MyPairs { get; set; }
因此,对于MyPairs中的每个元素,我创建了上面的DataTemplate

每当选择ListView更改时,我都会执行以下操作:

public void RefreshKeyValuePairs()
    {
        if (MyPairs != null)
        {
            MyPairs.Clear();
        }

        if (SelectedData != null)
        {
            foreach (MyValuePair item in SelectedData.MyPairs)
            {
                MyValuePairViewModel vm = new MyValuePairViewModel(item);
                MyPairs.Add(vm);
            }
        }
    }

但是,在这种情况下,每当我在创建的TextBox中键入内容时,它都不会在MyValuePairViewModel内部的MainViewModel的SelectedData内部更新,我必须在MyValuePairViewModel Set方法中手动将其同步到MainViewModel&#39; s SelectedData(但这也要求我在MyValuePairViewModel中有MainViewModel的实例)。

换句话说,我想直接绑定到创建的元素SelectedData.MyPairs[0].Description绑定到第一个创建的TextBlock,SelectedData.MyPairs[1].Description绑定到第二个创建的TextBlock,依此类推,以便它自动在两个方向上更新。如果SelectedData.MyPairs不是集合而是普通属性,我可以直接绑定它。

1 个答案:

答案 0 :(得分:1)

您可以将UI元素直接绑定到MyValuePair对象。您不需要特定的ViewModel类MyValuePairViewModel。

您唯一想念的是在MyValuePair上实现INotifyPropertyChanged。 UI将正常初始化,但初始化后对Description和Value属性的编程更新不会出现在UI中。 如果您不进行任何程序化更新,这将不会成为问题。

如果要对Description和Value属性进行更改,最简单的方法是直接在MyValuePair上实现INotifyPropertyChanged。 这只需要几行代码,并且比使用单独的类MyValuePairViewModel复制功能更容易。