I have a ViewModel which has an ObservableCollection<MyData> MainCollection
and MyData SelectedData
that holds the currently selected item from the MainCollection. MyData
consists of several properties and also of an 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).
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):
//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:
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; }
}
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.
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?
Edit At the moment I am using another 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:
public ObservableCollection<MyValuePairViewModel> MyPairs { get; set; }
.
So for every element inside MyPairs I create the above DataTemplate
Whenever the selection of the ListView changes I do the following:
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).
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. If SelectedData.MyPairs
were not a collection but a normal property I could bind to it directly.