I've got ComboBox and ListBox of CheckBoxes. Depending on SelectedItem of ComboBox ItemSource of ListBox must change. I made a sample to make thing easier. Here is the code:
ViewModel
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace Test
{
class Data
{
public long Id;
public object Value;
public override string ToString()
{
return Value.ToString();
}
}
class CheckedData: INotifyPropertyChanged
{
private Data myData;
public Data MyData
{
get { return myData; }
set
{
if (myData == value)
return;
myData = value;
RaisePropertyChanged(nameof(MyData));
}
}
private bool isChecked;
public bool IsChecked
{
get { return isChecked; }
set
{
isChecked = value;
RaisePropertyChanged(nameof(IsChecked));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
class BindingObject: INotifyPropertyChanged
{
private ObservableCollection<Data> dataList = new ObservableCollection<Data>();
public ObservableCollection<Data> DataList
{
get { return dataList; }
set
{
dataList = value;
RaisePropertyChanged(nameof(DataList));
}
}
private Data selectedItem;
public Data SelectedItem
{
get { return selectedItem; }
set
{
if (value == selectedItem)
return;
selectedItem = value;
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
class ViewModel: INotifyPropertyChanged
{
public ViewModel()
{
var tmp = new Data() {Id = 1, Value = "Cat"};
Obj.DataList.Add(tmp);
Obj.SelectedItem = tmp;
Obj.DataList.Add(new Data() {Id = 2, Value = "Dog"});
Mapping[1] = new ObservableCollection<CheckedData>()
{
new CheckedData() {IsChecked = true, MyData = new Data() {Id = 1, Value = "Maine coon"}},
new CheckedData() {IsChecked = true, MyData = new Data() {Id = 2, Value = "Siberian"}}
};
}
private BindingObject obj = new BindingObject();
public BindingObject Obj
{
get { return obj; }
set
{
if (obj == value)
return;
obj = value;
RaisePropertyChanged(nameof(Obj));
}
}
private Dictionary<long, ObservableCollection<CheckedData>> mapping = new Dictionary<long, ObservableCollection<CheckedData>>();
public Dictionary<long, ObservableCollection<CheckedData>> Mapping
{
get { return mapping; }
set
{
if (mapping == value)
return;
mapping = value;
RaisePropertyChanged(nameof(Mapping));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
View
<ComboBox x:Name="comboBox" ItemsSource="{Binding Path=Obj.DataList}" SelectedItem="{Binding Path=Obj.SelectedItem, Mode=TwoWay}"/>
<ListBox x:Name="listBox" Height="100" ItemsSource="{Binding Path=Mapping[Obj.SelectedItem.Id]}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" Content="{Binding Path=MyData.Value}" Margin="0,5,5,0"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
That is what I thought should work. ComboBox is okay, but ListBox ItemSource binding doesn't work. Only if I bind directly to list like this:
ViewModel
private ObservableCollection<CheckedData> test = new ObservableCollection<CheckedData>()
{
new CheckedData() {IsChecked = true, MyData = new Data() {Id = 1, Value = "Maine coon"}},
new CheckedData() {IsChecked = false, MyData = new Data() {Id = 2, Value = "Siberian"}}
};
public ObservableCollection<CheckedData> Test
{
get { return test; }
set
{
test = value;
RaisePropertyChanged(nameof(Test));
}
}
View
<ListBox x:Name="listBox" Height="100" ItemsSource="{Binding Path=Test}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" Content="{Binding Path=MyData.Value}" Margin="0,5,5,0"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Everything starts working.. Except Content binding, because I can't go deeper than 1 level of property path. So I have to override ToString() method in Data.
What should I fix to make everything work? Am I able to bind ItemSource like this? Why can't I go deeper than 1 lvl property binding in CheckBox?