2
votes

I feel like this should be a simple feature but I don't know how to bind to the selected items in a Listbox without using code behind.

I have a Listbox with Datatemplate containing a Checkbox. I want to get the list of the checked/selected items. How do I do this?

If I cannot get the SelectedItems, I want to bind to something that triggers "SelectedProduct" every time something gets selected so I can iterate through the "ProductList" and find the checked items. However, SelectedItem does not trigger every time I click on an item.

Here is my code:

<ListBox ItemsSource="{Binding ProductList}" SelectedItem="{Binding SelectedProduct}" SelectionMode="Multiple">
<ListBox.ItemTemplate>
    <DataTemplate>
        <CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" Content="{Binding ID}" Margin="2"/>
    </DataTemplate>
</ListBox.ItemTemplate>

<ListBox.ItemContainerStyle>
    <Style TargetType="{x:Type ListBoxItem}">
        <Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsChecked}"/>
    </Style>
</ListBox.ItemContainerStyle>

2

2 Answers

2
votes

A normal rational person would think SelectedItems should be bindable. Except... it isn't. And that sucks.

You have already hit on the usual approach, bind IsSelected to a property in your data object, then do something like:

myCollection.Where(i => i.Selected);

According to MSDN SelectedItem can return any selected item if the mode is set to "Multiple", so its trigger timing semantics are going to be undefined at best. Getting a notification when any part of the selection changes is going to be tricky, but you can always run logic when the Selected property gets changed (for example, raise an event the VM listens for).

1
votes

You can use Interactivity extension:

Add the reference to System.Windows.Interactivity.dll using reference wizard, search in Extensions section.

Then include the following namespace in your xaml:

 xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

And you can do this:

<ListBox x:Name="FooList">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged" >
            <i:InvokeCommandAction Command="{Binding FooCommand}" CommandParameter="{Binding SelectedItems, ElementName=FooList}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</ListBox>

In your ViewModel create a ICommand that get the current selected items.