Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the simplest way to bind a list of checkboxes to a list of checked values

Tags:

binding

wpf

I have a list of AvailableItems that I want to display as a list of checkboxes, so that users can pick which items to generate, which are then stored in another list called ItemsToGenerate (my lists are actually just lists of strings).

Showing all available items with corresponding checkboxes is easy:

<ItemsControl ItemsSource="{Binding Path=AvailableItems}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <CheckBox Content="{Binding}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>    
</ItemsControl>

But now I need to bind each Checkbox.IsChecked property, to the fact that the item is in the ItemsToGenerate list. I thought of making a ListContainmentToBoolConverter like this:

IsChecked="{Binding Path=ItemsToGenerate, 
            Converter={StaticResource ListContainmentToBoolConverter}}"

But that doesn't work because I'm missing a ConverterParameter to pass the value of each item, but I can't do that, because ConverterParameter does not support binding.

Any ideas?

like image 269
Anthony Brien Avatar asked Apr 23 '09 18:04

Anthony Brien


1 Answers

I've found a solution to my problem.

I've changed my ItemsControl to a ListBox, and added a binding between the SelectedItems with my ItemsToGenerate collection using the technique described here. It basically allows me to synchronize any custom collection to ListBox.SelectedItems using a simple attached property.

<ListBox ItemsSource="{Binding AvailableItems}"
         Behaviors:MultiSelectorBehaviours.SynchronizedSelectedItems=
             "{Binding ItemsToGenerate}"
         SelectionMode="Multiple"
         Background="{x:Null}">  
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel />                    
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <CheckBox Content="{Binding}"
                      Margin="3"
                      IsChecked="{Binding RelativeSource=
                           {RelativeSource Mode=FindAncestor,
                            AncestorType={x:Type ListBoxItem}},
                           Path=IsSelected}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ListBox>

I'm still able to display this as I initially wanted (a list of checkboxes), by adding a data template to change each ListBoxItem to a checkbox and binding each Checkbox.IsChecked to ListBoxItem.IsSelected.

I had this pattern in so many places in my application that this is the ideal solution for me, because now I just need to specify one attached property, and the rest is all handled by the data bindings, and I don't need any additional code.

like image 168
Anthony Brien Avatar answered Oct 25 '22 19:10

Anthony Brien