I have a select 'All' checkbox that I would like to be bound to the (IsChecked || !IsEnabled) of other checkboxes.
Checking 'All' checks all enabled checkboxes.
Unchecking 'All' unchecks all checkboxes.
Manually checking each enabled checkbox will check 'All'.
When all enabled checkboxes and 'All' are checked and user unchecks any checkbox, 'All' automatically unchecks.
I am new to WPF Databinding. I was thinking maybe I just handle the click of 'All' to set the other checkboxes. But I don't know how to bind to both properties of multiple sources. When I click 'All' and manually uncheck another checkbox, 'All' needs to uncheck.
Here's a way to do it in Xaml with Converters. This is assuming that all your CheckBox's are added directly as Controls in Xaml (it's not very dynamic, won't work for DataTemplate's etc). First we create three CheckBoxes (CheckBox1, CheckBox2, CheckBox3) that will be Checked/Unchecked when Checking the CheckAllCheckBox. It will also work in reverse.
Update
The last part (ignore disabled CheckBox) was a bit of a problem here and I'm not crazy about this solution but I can't see a better way. We store the values from Convert and re-use them in ConvertBack for the disabled CheckBox's. Doing this, we should also add the x:Shared="False" attribute for the CheckAllConverter since a new instance is required for every MultiBinding that would use it (unlikely in this case but still..)
<Window.Resources>
<local:CheckAllConverter x:Key="CheckAllConverter" x:Shared="False"/>
</Window.Resources>
<StackPanel>
<CheckBox Content="Check All"
Name="CheckAllCheckBox">
<CheckBox.IsChecked>
<MultiBinding Converter="{StaticResource CheckAllConverter}">
<Binding ElementName="CheckBox1" Path="IsChecked" />
<Binding ElementName="CheckBox1" Path="IsEnabled" Mode="OneWay"/>
<Binding ElementName="CheckBox2" Path="IsChecked" />
<Binding ElementName="CheckBox2" Path="IsEnabled" Mode="OneWay"/>
<Binding ElementName="CheckBox3" Path="IsChecked" />
<Binding ElementName="CheckBox3" Path="IsEnabled" Mode="OneWay"/>
</MultiBinding>
</CheckBox.IsChecked>
</CheckBox>
<CheckBox Content="CheckBox 1"
Name="CheckBox1"/>
<CheckBox Content="CheckBox 2"
Name="CheckBox2"/>
<CheckBox Content="CheckBox 3"
Name="CheckBox3"/>
</StackPanel>
The Converter for CheckAll
public class CheckAllConverter : IMultiValueConverter
{
private object[] convertValues = null;
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
convertValues = new object[values.Length];
for(int i = 0; i < values.Length; i++)
{
convertValues[i] = values[i];
}
for (int i = 0; i < values.Length; i += 2)
{
bool isChecked = (bool)values[i];
bool isEnabled = (bool)values[i + 1];
if (isEnabled == false)
{
continue;
}
if (isChecked == false)
{
return false;
}
}
return true;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
object[] values = new object[targetTypes.Length];
for (int i = 0; i < values.Length; i += 2)
{
if (convertValues != null && (bool)convertValues[i + 1] == false)
{
values[i] = convertValues[i];
}
else
{
values[i] = value;
}
// IsEnabled is OneWay and won't care about this value
values[i + 1] = null;
}
return values;
}
}