Press Shift to select multiple check boxes in WPF

Hi everyone, I’m creating a form in WPF but I can’t press Shift to select multiple boxes like the form SelectionFromList in pyrevit does though I have set the SelectionMode to Extended. Can you look at the XAML code below and tell me why?

<Window x:Class="Practice.CopyFilterCurrentModel.CopyFilterCurrentModelWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:local="clr-namespace:Practice.CopyFilterCurrentModel"
        mc:Ignorable="d" 
        Width="600"
        Height="550"
        ShowInTaskbar="True"
        WindowStartupLocation="CenterScreen"
        Title="Copy Filter Current Model"
        ResizeMode="CanResize">

    <Grid>
        <!-- Define rows in the Grid -->
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <!-- Source GroupBox -->
            <RowDefinition Height="*"/>
            <!-- Destination GroupBox -->
            <RowDefinition Height="Auto"/>
            <!-- Buttons -->
        </Grid.RowDefinitions>

        <!-- GroupBox with Source Header -->
        <GroupBox Header="Source" BorderBrush="Gray" VerticalAlignment="Stretch" Margin="10" Grid.Row="0">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="*"/>
                    <!-- Ensures ListView expands -->
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="150"/>
                    <!-- Label width -->
                    <ColumnDefinition Width="*"/>
                    <!-- ComboBox and ListView width -->
                </Grid.ColumnDefinitions>

                <!-- Source View ComboBox -->
                <Label Content="Source View: " Margin="10 0 0 0" VerticalAlignment="Center"/>
                <ComboBox x:Name="cbb_SourceView" Grid.Column="1" Margin="0 5 17 5" SelectionChanged="cbb_SourceView_SelectionChanged" HorizontalAlignment="Stretch"/>

                <!-- Filter ListView with ScrollViewer -->
                <Label Content="Filters: " Grid.Row="1" Margin="10 10 0 0" VerticalAlignment="Top"/>
                <ScrollViewer x:Name="sv_Filters" Grid.Column="1" Grid.Row="1" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Disabled" CanContentScroll="True">
                    <ListView x:Name="lv_Filters" 
                              SelectionMode="Extended" 
                              PreviewMouseWheel="ListBox_PreviewMouseWheel" 
                              MinHeight="200">
                        <ListView.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal">
                                    <CheckBox IsChecked="{Binding IsChecked}"
                                              VerticalAlignment="Center" 
                                              Margin="0,0,5,0"/>
                                    <TextBlock Text="{Binding}" VerticalAlignment="Center" IsHitTestVisible="False"/>
                                </StackPanel>
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>

                </ScrollViewer>
            </Grid>
        </GroupBox>

        <!-- GroupBox with Destination Header-->
        <GroupBox Header="Destination" BorderBrush="Gray" VerticalAlignment="Stretch" Margin="10" Grid.Row="1">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="150"/>
                    <!-- Label width -->
                    <ColumnDefinition Width="*"/>
                    <!-- ComboBox and ListView width -->
                </Grid.ColumnDefinitions>

                <Label Content="Destination Views: " Margin="10 0 0 0" VerticalAlignment="Center"/>

                <ScrollViewer x:Name="sv_DestinationViews" Grid.Column="1" Grid.Row="1" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" CanContentScroll="True">
                    <ListView x:Name="lv_DestinationViews" SelectionMode="Extended" PreviewMouseWheel="ListBox_PreviewMouseWheel" MinHeight="200">
                        <ListView.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal">
                                    <CheckBox IsChecked="{Binding IsChecked}" VerticalAlignment="Center" Margin="0,0,5,0"/>
                                    <TextBlock Text="{Binding}" VerticalAlignment="Center" IsHitTestVisible="False"/>
                                </StackPanel>
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>
                </ScrollViewer>
            </Grid>
        </GroupBox>

        <!-- OK and Cancel buttons -->
        <StackPanel Grid.Row="2" Margin="5,5,5,5" VerticalAlignment="Bottom" HorizontalAlignment="Right" Orientation="Horizontal">
            <Button x:Name="bt_Ok" Content="OK" Width="100" Click="bt_Ok_Click"/>
            <Button x:Name="bt_Cancel" Content="Cancel"  Width="100" Margin="5 0 0 0" Click="bt_Cancel_Click"/>
        </StackPanel>
    </Grid>
</Window>

I am experimenting with the latest opening model on topics I am not top notch at

I will let you judge if it works

The issue arises because you’re wrapping your ListView controls inside ScrollViewer elements. Wrapping a ListView (or any ItemsControl) inside a ScrollViewer can interfere with its built-in selection behaviors, including the ability to select multiple items using the Shift key. This happens because the ScrollViewer can disrupt the event handling and virtualization that the ListView relies on.

Solution: Remove the ScrollViewer wrappers around your ListView controls.

The ListView control already includes its own scrolling functionality, so you don’t need an additional ScrollViewer. By removing it, you allow the ListView to manage scrolling and selection events properly.

Here’s how you can modify your XAML:

Before (with ScrollViewer):

<!-- Filter ListView with ScrollViewer -->
<Label Content="Filters: " Grid.Row="1" Margin="10 10 0 0" VerticalAlignment="Top"/>
<ScrollViewer x:Name="sv_Filters" Grid.Column="1" Grid.Row="1" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Disabled" CanContentScroll="True">
    <ListView x:Name="lv_Filters" 
              SelectionMode="Extended" 
              PreviewMouseWheel="ListBox_PreviewMouseWheel" 
              MinHeight="200">
        <!-- ListView ItemTemplate -->
    </ListView>
</ScrollViewer>

After (without ScrollViewer):

<!-- Filter ListView without ScrollViewer -->
<Label Content="Filters: " Grid.Row="1" Margin="10 10 0 0" VerticalAlignment="Top"/>
<ListView x:Name="lv_Filters" 
          Grid.Column="1" 
          Grid.Row="1"
          SelectionMode="Extended" 
          PreviewMouseWheel="ListBox_PreviewMouseWheel" 
          MinHeight="200">
    <!-- ListView ItemTemplate -->
</ListView>

Do the same for the lv_DestinationViews ListView:

Before:

<ScrollViewer x:Name="sv_DestinationViews" Grid.Column="1" Grid.Row="1" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" CanContentScroll="True">
    <ListView x:Name="lv_DestinationViews" SelectionMode="Extended" PreviewMouseWheel="ListBox_PreviewMouseWheel" MinHeight="200">
        <!-- ListView ItemTemplate -->
    </ListView>
</ScrollViewer>

After:

<ListView x:Name="lv_DestinationViews" 
          Grid.Column="1" 
          Grid.Row="1"
          SelectionMode="Extended" 
          PreviewMouseWheel="ListBox_PreviewMouseWheel" 
          MinHeight="200">
    <!-- ListView ItemTemplate -->
</ListView>

Why This Works:

  • Built-in Scrolling: The ListView control has inherent scrolling capabilities. By adding a ScrollViewer, you’re essentially nesting scrollable areas, which can cause input events (like key presses) to be captured incorrectly.

  • Event Handling: The ScrollViewer can prevent the ListView from receiving key events needed for extended selection, such as Shift or Ctrl key combinations.

Additional Tips:

  • CheckBox Interaction: If you still experience issues, consider setting IsHitTestVisible="False" or Focusable="False" on the CheckBox within your DataTemplate. This ensures that the CheckBox doesn’t interfere with item selection.

    <CheckBox IsChecked="{Binding IsChecked}"
              VerticalAlignment="Center" 
              Margin="0,0,5,0"
              IsHitTestVisible="False"/>
    
  • Synchronization: You might also want to synchronize the IsSelected property of the ListViewItem with the IsChecked property of the CheckBox to keep selection and checking in sync.

By making these changes, your ListView controls should now support multiple item selection using the Shift key as expected.

hi @Jean-Marc , I just did as you said but nothing changes. I tried setting IsHitTestVisible="False" but could not even click the boxes, then I tried with Focusable="False" but could not use the Shift key. This is my code at the moment, can you help me?

<Window x:Class="Practice.CopyFilterCurrentModel.CopyFilterCurrentModelWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:local="clr-namespace:Practice.CopyFilterCurrentModel"
        mc:Ignorable="d" 
        Width="600"
        Height="550"
        ShowInTaskbar="True"
        WindowStartupLocation="CenterScreen"
        Title="Copy Filter Current Model"
        ResizeMode="CanResize">

    <Grid>
        <!-- Define rows in the Grid -->
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <!-- Source GroupBox -->
            <RowDefinition Height="*"/>
            <!-- Destination GroupBox -->
            <RowDefinition Height="Auto"/>
            <!-- Buttons -->
        </Grid.RowDefinitions>

        <!-- GroupBox with Source Header -->
        <GroupBox Header="Source" BorderBrush="Gray" VerticalAlignment="Stretch" Margin="10" Grid.Row="0">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="*"/>
                    <!-- Ensures ListView expands -->
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="150"/>
                    <!-- Label width -->
                    <ColumnDefinition Width="*"/>
                    <!-- ComboBox and ListView width -->
                </Grid.ColumnDefinitions>

                <!-- Source View ComboBox -->
                <Label Content="Source View: " Margin="10 0 0 0" VerticalAlignment="Center"/>
                <ComboBox x:Name="cbb_SourceView" Grid.Column="1" Margin="0 5 17 5" SelectionChanged="cbb_SourceView_SelectionChanged" HorizontalAlignment="Stretch"/>

                <!-- Filter ListView -->
                <Label Content="Filters: " Grid.Row="1" Margin="10 10 0 0" VerticalAlignment="Top"/>
                <ListView x:Name="lv_Filters" Grid.Column="1" Grid.Row="1" SelectionMode="Extended">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <CheckBox IsChecked="{Binding IsChecked}" 
                                          VerticalAlignment="Center" 
                                          Margin="0,0,5,0"
                                          Focusable="False"/>
                                <TextBlock Text="{Binding}" VerticalAlignment="Center" />
                            </StackPanel>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </Grid>
        </GroupBox>

        <!-- GroupBox with Destination Header-->
        <GroupBox Header="Destination" BorderBrush="Gray" VerticalAlignment="Stretch" Margin="10" Grid.Row="1">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="150"/>
                    <!-- Label width -->
                    <ColumnDefinition Width="*"/>
                    <!-- ComboBox and ListView width -->
                </Grid.ColumnDefinitions>

                <Label Content="Destination Views: " Margin="10 0 0 0" VerticalAlignment="Center"/>
                <ListView x:Name="lv_DestinationViews" Grid.Column="1" Grid.Row="1" SelectionMode="Extended">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <CheckBox IsChecked="{Binding IsChecked}" 
                                          VerticalAlignment="Center" 
                                          Margin="0,0,5,0"
                                          Focusable="False"/>
                                <TextBlock Text="{Binding}" VerticalAlignment="Center" />
                            </StackPanel>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </Grid>
        </GroupBox>

        <!-- OK and Cancel buttons -->
        <StackPanel Grid.Row="2" Margin="5,5,5,5" VerticalAlignment="Bottom" HorizontalAlignment="Right" Orientation="Horizontal">
            <Button x:Name="bt_Ok" Content="OK" Width="100" Click="bt_Ok_Click"/>
            <Button x:Name="bt_Cancel" Content="Cancel"  Width="100" Margin="5 0 0 0" Click="bt_Cancel_Click"/>
        </StackPanel>
    </Grid>
</Window>

Sorry I can’t, and we would need the python code anyway

@Jean-Marc I did it in c#. I know this forum is about python but can you help me with it? I have asked in Revit API Forum but still haven’t received any answers. Here is the link with my full code: