简体   繁体   English

WPF MVVM绑定到DataTemplate的集合

[英]WPF MVVM Binding collection to DataTemplate

I have a ViewModel which has an ObservableCollection<MyData> MainCollection and MyData SelectedData that holds the currently selected item from the MainCollection. 我有一个ViewModel,它具有一个ObservableCollection<MyData> MainCollectionMyData SelectedData ,其中包含从MainCollection当前选择的项目。 MyData consists of several properties and also of an ObservableCollection<MyValuePair> MyPairs . MyData包含多个属性,还包含ObservableCollection<MyValuePair> MyPairs MyValuePair consists of 2 properties Description and Value just like a KeyValuePair (Cannot use a Dictionary because I want to have TwoWay binding). MyValuePair由2个属性DescriptionValue组成,就像KeyValuePair一样(无法使用字典,因为我想具有TwoWay绑定)。

I want to dynamically create controls foreach MyValuePair according to my DataTemplate (I am trying to do it like here: Adding controls dynamically in WPF MVVM ): 我想根据我的DataTemplate动态地为每个MyValuePair创建控件(我正在尝试这样做: 在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>

MyData: 迈德特:

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

MainViewModel: 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: 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; }
    }

but the problem is I do not want to create another ViewModel (MyValuePairViewModel) for my MyValuePair because then I have to synchronize it with my MainViewModel everytime the SelectedData changes or if the MyPair (of type MyValuePair) changes I have to sync it back to the MainViewModel and it does not feel right. 但问题是我不想为我创建另一个视图模型(MyValuePairViewModel) MyValuePair ,因为那时我已经把它与我的MainViewModel每次的SelectedData改变或者如果MyPair(类型MyValuePair)的同步变化我必须把它同步回MainViewModel,感觉不对。

So is there an easy way to bind my DataTemplate directly to each element inside of the ObservableCollection<MyValuePair> property in SelectedData so that the DataTemplate is created for each MyPairs? 那么,是否有一种简单的方法可以将我的DataTemplate直接绑定到SelectedData中ObservableCollection<MyValuePair>属性内的每个元素,以便为每个MyPair创建DataTemplate?


Edit At the moment I am using another ViewModel: 编辑目前,我正在使用另一个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;
    }
}

and added it inside my MainViewModel like this: 并将其添加到我的MainViewModel中,如下所示:
public ObservableCollection<MyValuePairViewModel> MyPairs { get; set; } public ObservableCollection<MyValuePairViewModel> MyPairs { get; set; } . public ObservableCollection<MyValuePairViewModel> MyPairs { get; set; }
So for every element inside MyPairs I create the above DataTemplate 因此,对于MyPairs中的每个元素,我都创建了上面的DataTemplate

Whenever the selection of the ListView changes I do the following: 每当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);
            }
        }
    }

However, in this case whenever I type something inside the created TextBox it is not updated inside the MainViewModel's SelectedData only inside MyValuePairViewModel and I have to manually sync it inside the MyValuePairViewModel Set method to the MainViewModel's SelectedData (but this also requires that I have the instance of the MainViewModel inside MyValuePairViewModel). 但是,在这种情况下,每当我在创建的TextBox中键入内容时,它都不会在MainViewModel的SelectedData中仅在MyValuePairViewModel内更新,并且我必须在MyValuePairViewModel Set方法内手动将其同步到MainViewModel的SelectedData(但这还要求我拥有实例在MyValuePairViewModel内部的MainViewModel)。

In other words I want to bind directly to the created elements SelectedData.MyPairs[0].Description bind to first created TextBlock, SelectedData.MyPairs[1].Description bind to second created TextBlock and so on so that it automatically updates in both directions. 换句话说,我想直接绑定到创建的元素SelectedData.MyPairs[0].Description绑定到第一个创建的TextBlock, SelectedData.MyPairs[1].Description绑定到第二个创建的TextBlock,依此类推,以便它自动在两个方向上更新。 If SelectedData.MyPairs were not a collection but a normal property I could bind to it directly. 如果SelectedData.MyPairs不是集合,而是普通属性,则可以直接绑定到它。

You can bind your UI element directly to the MyValuePair object. 您可以将UI元素直接绑定到MyValuePair对象。 You do not need a specific ViewModel class MyValuePairViewModel. 您不需要特定的ViewModel类MyValuePairViewModel。

The only thing that you will miss is the implementation of INotifyPropertyChanged on MyValuePair. 您唯一会错过的是MyValuePair上INotifyPropertyChanged的实现。 The UI will be initialized normally, but programmatic updates to the Description and Value properties after the initialisation will not appear in the UI. UI将正常初始化,但是初始化后对Description和Value属性的编程更新将不会出现在UI中。 This won't be a problem, if you don't make any programmatic updates. 如果您不进行任何程序更新,这将不是问题。

If you are going to make changes to the Description and Value properties, the easiest thing would be to implement the INotifyPropertyChanged directly on MyValuePair. 如果要更改Description和Value属性,最简单的方法是直接在MyValuePair上实现INotifyPropertyChanged。 This only requires a few lines of code and would be easier than duplicating the functionality with a separate class MyValuePairViewModel. 这仅需要几行代码,并且比使用单独的类MyValuePairViewModel复制功能要容易。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM