Problème de sélection WPF ListBoxItem
Question
J'ai une liste déroulante où les éléments contiennent des cases à cocher:
<ListBox Style="{StaticResource CheckBoxListStyle}" Name="EditListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Click="Checkbox_Click" IsChecked="{Binding Path=IsChecked, Mode=TwoWay}" Content="{Binding Path=DisplayText}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Le problème que je rencontre est que lorsque je clique sur la case à cocher ou sur son contenu, le parent ListBoxItem n'est pas sélectionné. Si je clique sur l'espace blanc à côté de la case à cocher, le ListBoxItem est sélectionné.
Le comportement que j'essaie d'obtenir est de pouvoir sélectionner un ou plusieurs éléments dans la liste et d'utiliser la barre d'espacement pour activer ou désactiver les cases à cocher.
Quelques informations supplémentaires:
private void Checkbox_Click(object sender, RoutedEventArgs e)
{
CheckBox chkBox = e.OriginalSource as CheckBox;
}
Dans le code ci-dessus, lorsque je clique sur une case à cocher, e.Handled est false et chkBox.Parent est null.
La réponse de Kent m'a mis dans la bonne voie, voici ce que j'ai fini avec:
<ListBox Style="{StaticResource CheckBoxListStyle}" Name="EditListBox" PreviewKeyDown="ListBox_PreviewKeyDown">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Path=IsChecked, Mode=TwoWay}" />
<TextBlock Text="{Binding DisplayText}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Je devais utiliser PreviewKeyDown car, par défaut, lorsque vous appuyez sur la barre d'espace dans une zone de liste, tout est désélectionné, à l'exception du dernier élément sélectionné.
La solution
Pour commencer, placez le contenu en dehors de la CheckBox
:
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChecked}"/>
<TextBlock Text="{Binding DisplayText}"/>
</StackPanel>
Après cela, vous devrez vous assurer que si vous appuyez sur l'espace sur un ListBoxItem
, le contrôle CheckBox
est activé. Il existe plusieurs façons de procéder, notamment un simple gestionnaire d’événements sur ListBoxItem
. Vous pouvez également spécifier un gestionnaire pour UIElement.KeyUp
ou autre dans votre DataTemplate
:
<CheckBox IsChecked="{Binding IsChecked}" UIElement.KeyUp="..."/>
Autres conseils
Vous pouvez également lier les propriétés IsChecked de CheckBox et IsSelected du ListBoxItem:
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding DisplayText}" IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Dans votre cas d'utilisation, il serait beaucoup plus simple d'utiliser un ItemsControl
au lieu d'une zone de liste. Un ItemsControl est similaire à une Listbox, sauf qu'il ne contient pas le comportement de sélection automatique. Cela signifie que son utilisation pour héberger une liste de ce qui sont essentiellement des cases à cocher est très simple et vous n'avez pas à contourner le comportement de sélection du ListBox.
En passant simplement à ItemsControl, vous obtiendrez exactement ce dont vous avez besoin:
<ItemsControl Style="{StaticResource CheckBoxListStyle}" Name="EditListBox">
<ItemsControl .ItemTemplate>
<DataTemplate>
<CheckBox Click="Checkbox_Click" IsChecked="{Binding Path=IsChecked, Mode=TwoWay}" Content="{Binding Path=DisplayText}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Vous pouvez cliquer sur le texte pour cocher les cases à cocher (comportement par défaut) et vous pouvez aussi utiliser le clavier sans avoir à connecter de gestionnaire d'événement.