WPF ListBox Selection via CheckBox
Here's a simple solution to add check boxes to a ListBox (or other similar controls) in WPF. This solution will keep the selection of the check box in sync with the list box's SelectedItems
.
TLDR
The TLDR is that you should add a CheckBox
control to your DataTemplate
and then bind the box's IsChecked
property to the ListBoxItem.IsSelected
property, using a relative source binding.
MainWindow.xaml
In this file, we've got a ListBox
that is bound to an Items
property on the Window
. The ListBox's SelectionMode
property has been set to Multiple
to allow multiple items to be selected at a time. Additionally, the ListBox.ItemTemplate
has been set to a custom DataTemplate
which contains our CheckBox
. The IsChecked
property is bound to the IsSelected
property of the ListBoxItem
.
ListBox
controls automatically create a ListBoxItem
for every item provided in the ListBox.ItemsSource
. Every ListBoxItem.IsSelected
is kept in sync with the containing ListBox
control and that IsSelected
property can be modified to change what's selected within the ListBox
.
By using a RelativeSource
binding on our IsChecked
property, we tell the CheckBox
to crawl up the tree until the containing ListBoxItem
is located (via the AncestorType
). Once the item is located, we simply bind to the item's IsSelected
property, effectively synchronizing our CheckBox.IsChecked
state to the ListBoxItem.IsSelected
state.
<Window x:Class="MultiSelectionSpike.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MultiSelectionSpike"
d:DataContext="{d:DesignInstance local:MainWindow}"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<ListBox ItemsSource="{Binding Path=Items}" SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<DockPanel>
<CheckBox IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}, Path=IsSelected}" DockPanel.Dock="Left" />
<TextBlock Text="{Binding}" />
</DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Window>
MainWindow.xaml.cs
A few points to note about this class. First, it defines the Items
property that is used by the ItemsSource
in our xaml. Next, it initializes a new collection with some sample items in it. Finally, it sets MainWindow
's DataContext
to itself, enabling the ItemsSource
binding to work correctly.
using System.Collections.ObjectModel;
namespace MultiSelectionSpike
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow
{
public MainWindow()
{
Items = new ObservableCollection<string> {"First", "Second", "Third"};
InitializeComponent();
DataContext = this;
}
public ObservableCollection<string> Items { get; }
}
}