I have a collection of variables in my viewmodel:
public ObservableCollection<ObservableVariable> Variables { get; }= new ObservableCollection<ObservableVariable>();
The ObservableVariable class has two properties: string Name, and bool Selected; the class implements INotifyPropertyChanged,
My goal is to have this collection bound to a checklist in a WPF view, and to have a 'select all' checkbox bound to that list implemented using MultiBinding. The following image illustrates the desired view.
Observe the XAML below:
<CheckBox Content="Select All" Name="SelectAllCheckbox"></CheckBox>
...
<ListBox ItemsSource="{Binding Variables}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}">
<CheckBox.IsChecked>
<MultiBinding Converter="{StaticResource LogicalOrConverter}" Mode="TwoWay">
<Binding Path="Selected"></Binding>
<Binding ElementName="SelectAllCheckbox" Path="IsChecked"></Binding>
</MultiBinding>
</CheckBox.IsChecked>
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The LogicalOrConverter takes any number of bools; if any are true, return true.
As you can see above each checkbox is bound to a variable in the viewmodel and the state of the 'select all' checkbox. Currently, everything works as desired EXCEPT the following: If I click 'Select All,' the checkboxes update in the view, but the change does NOT propagate back to the viewmodel.
Note, most things in my implementation work correctly. For example, if I click an individual checkbox, the viewmodel is updated correctly.
The problem in more detail:
When I click an individual checkbox the OnPropertyChanged event is fired in the variable whose box was just changed; the ConvertBack function in the converter is fired; the viewmodel is updated and all is well.
However, when I click the "Select All" checkbox, the individual checkboxes are updated in the view, but OnPropertyChanged is not called in any variable, and the ConvertBack function in the converter is not called.
Also relevent, if I uncheck "Select All," the individual checks go back to what they were before.
The only way to update the viewmodel is to click in the individual checkboxes. However, the multibinding works for the purposes of the view.
My question is:
Why aren't changes to the checkbox propagated to the source collection in the viewmodel
The converter:
public class LogicalOrConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
foreach (object arg in values)
{
if ((arg is bool) && (bool)arg == true)
{
return true;
}
}
return false;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
object[] values = new object[2] {false, false};
if (value is bool && (bool) value == true)
values[0] = true;
return values;
}
}
ObservableVariable definition:
public class ObservableVariable : INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged(nameof(Name));
}
}
private bool _selected;
public bool Selected
{
get { return _selected; }
set
{
_selected = value;
OnPropertyChanged(nameof(Selected));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}