Pavel Voronin
Pavel Voronin

Reputation: 13983

Select/Unselect all CheckBox in a "CheckListBox" in XAML only

I searched this topic and found several discussions. What I didn't like about those implementations is that they either implied special kind of the bound data (with IsSelected property) or lacked normal keyboard support.

CheckBox in a list is more a decorative thing rather than functionalyty extension thus it should be treated accordingly.

I started from this nice and helpful article: http://www.gbogea.com/2010/01/02/mvvm-multiselect-listbox

But I beleive hacking View in favor of the ViewModel is not quite good practice. It's ViewModel to be adapted to View and Model. Surely, IMHO.

So I changed a little and finished with this XAML:

<ListBox Name="checkboxList"
                 ItemsSource="{Binding Sports}"
                 Margin="0,5"
                 SelectionMode="Multiple">
            <ListBox.ItemContainerStyle>
                <Style>
                    <Setter Property="ListBoxItem.Background" Value="Transparent"/>
                    <Setter Property="ListBoxItem.Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                                <Border x:Name="Bd" 
                                SnapsToDevicePixels="true" 
                                Background="{TemplateBinding Background}" 
                                BorderBrush="{TemplateBinding BorderBrush}" 
                                BorderThickness="{TemplateBinding BorderThickness}"
                                Padding="{TemplateBinding Padding}">
                                    <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
                                              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                </Border>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </ListBox.ItemContainerStyle>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}, Path=IsSelected, Mode=TwoWay}" 
                              Content="{Binding}"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

Here CheckBox selection is in sync with ListBoxItem.IsSelected and ListBox is unaware of the bound data peculiarities.

This is Ok. But Is there any way to add Select|Deselect All for the ListBox by adding one more checkbox to the control template? Using only XAML.

Upvotes: 0

Views: 2158

Answers (1)

brunnerh
brunnerh

Reputation: 184534

You could do something like that using for example Interactivity from the Blend SDK

<ListBox ItemsSource="{Binding Data}" SelectionMode="Extended">
    <ListBox.Template>
        <ControlTemplate TargetType="ListBox">
            <StackPanel>
                <CheckBox Content="All">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="Checked">
                            <is:CallMethodAction MethodName="SelectAll"
                                    TargetObject="{Binding RelativeSource={RelativeSource TemplatedParent}}" />
                        </i:EventTrigger>
                        <i:EventTrigger EventName="Unchecked">
                            <is:CallMethodAction MethodName="UnselectAll"
                                    TargetObject="{Binding RelativeSource={RelativeSource TemplatedParent}}" />
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </CheckBox>
                <ItemsPresenter />
            </StackPanel>
        </ControlTemplate>  
    </ListBox.Template>
</ListBox>

This however does not solve a problem you did not mention or think of, namely that the state of that CheckBox will not change when the selection is changed without using it. You could instead bind the IsChecked state using a MultiBinding and value converter to get it into the right state, you then could also drop the events. It is also rather messy though.

Upvotes: 1

Related Questions