WPF DataGrid勾选复选框无法实现多行选中问题求助
WPF DataGrid多选异常问题
我在WPF中使用DataGrid,需求是勾选行内复选框时选中对应行并支持多选,但目前始终只能选中一行。勾选新行后,之前已勾选行的IsSelected属性会变为false。后台代码中,我在复选框Checked事件里将对应行的IsSelected设为true,但新勾选会清除之前的选中状态,不清楚原因。
XAML代码
<DataGrid VirtualizingStackPanel.VirtualizationMode="Standard" EnableColumnVirtualization = "True" EnableRowVirtualization ="True" x:Name="deckGrid" Grid.Row="3" ItemsSource="{Binding DeckList}" AutoGenerateColumns="False" SelectionMode="Extended" Margin="10,10,0,0" SelectionUnit="FullRow" SelectionChanged="deckGrid_SelectionChanged"> <DataGrid.Columns > <DataGridTemplateColumn Width="70" > <DataGridTemplateColumn.HeaderTemplate > <DataTemplate> <CheckBox Name="ckbSelectedAll" IsThreeState="True" Margin="10,0,0,0" IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:DeckDefinition}, Path=AllSelected}"> <i:Interaction.Triggers> <i:EventTrigger EventName="Unchecked"> <i:InvokeCommandAction Command="{x:Static local:DeckDefinition.UnCheckedCommand}"/> </i:EventTrigger> <i:EventTrigger EventName="Checked"> <i:InvokeCommandAction Command="{x:Static local:DeckDefinition.CheckedCommand}"/> </i:EventTrigger> </i:Interaction.Triggers> </CheckBox> </DataTemplate> </DataGridTemplateColumn.HeaderTemplate> <DataGridTemplateColumn.CellTemplate > <DataTemplate> <CheckBox IsChecked="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged}" Name="cbkSelect" Margin="10,0,0,0" Checked="CheckedTest"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTextColumn Header="{lex:LocText Key=name, Dict=general, Assembly=KillCardMain}" Binding="{Binding Path=Name}" ></DataGridTextColumn> <DataGridTemplateColumn HeaderStyle="{StaticResource CollapsedHeaderStyle}" CellStyle="{StaticResource NoBackgroundCellStyle}"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Button Width="32" Style="{DynamicResource NoBackgroundButtonStyle}" Click="DeleteRowBtnClicked"> <Image Source="/KillCardMain;component/Resources/Images/delete.png" Width="16"></Image> </Button> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTemplateColumn HeaderStyle="{StaticResource CollapsedHeaderStyle}" CellStyle="{StaticResource NoBackgroundCellStyle}"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Button Width="32" Style="{DynamicResource NoBackgroundButtonStyle}"> <Image Source="/KillCardMain;component/Resources/Images/edit.png" Width="16"></Image> </Button> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>
后台代码
private void CheckedTest(object sender, RoutedEventArgs e) { int index = deckGrid.SelectedIndex; DataGridRow row = (DataGridRow)deckGrid.ItemContainerGenerator.ContainerFromIndex(index); row.IsSelected = true; }
问题原因及解决方法
核心问题
当前代码中,deckGrid.SelectedIndex仅返回最后一次点击选中的行索引,直接设置row.IsSelected = true时,DataGrid默认会取消之前的选中行(未启用多选批量操作逻辑)。加上开启了行虚拟化,ItemContainerGenerator.ContainerFromIndex可能无法正确获取所有行容器,进一步导致多选失效。
推荐解决方案(MVVM绑定方式)
直接在数据模型中维护IsSelected属性,同步绑定到DataGrid行的IsSelected和复选框的IsChecked,无需手动操作UI:
- 数据模型改造(假设你的数据项类型是
DeckItem):
using System.ComponentModel; using System.Runtime.CompilerServices; public class DeckItem : INotifyPropertyChanged { private bool _isSelected; public bool IsSelected { get => _isSelected; set { _isSelected = value; OnPropertyChanged(); } } // 你的其他属性(如Name) private string _name; public string Name { get => _name; set { _name = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
- 修改DataGrid绑定:
在XAML的DataGrid中添加行样式绑定,同时修改复选框的绑定路径:
<DataGrid ...> <!-- 添加行样式,绑定IsSelected --> <DataGrid.RowStyle> <Style TargetType="DataGridRow"> <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/> </Style> </DataGrid.RowStyle> <DataGrid.Columns> <DataGridTemplateColumn Width="70"> <!-- 其他部分不变,修改复选框的IsChecked绑定 --> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <CheckBox IsChecked="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged}" Name="cbkSelect" Margin="10,0,0,0"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <!-- 其他列保持不变 --> </DataGrid.Columns> </DataGrid>
这样勾选复选框会自动同步行选中状态,天然支持多选,无需后台事件处理。
备选方案(后台事件处理)
如果坚持用事件驱动方式,取消原获取SelectedIndex的逻辑,改为通过数据项操作SelectedItems集合:
- 修改后台代码:
private void CheckedTest(object sender, RoutedEventArgs e) { var checkBox = sender as CheckBox; var item = checkBox.DataContext as DeckItem; // 替换为你的数据模型类型 if (item != null && !deckGrid.SelectedItems.Contains(item)) { deckGrid.SelectedItems.Add(item); } } // 新增Unchecked事件处理,移除选中项 private void UncheckedTest(object sender, RoutedEventArgs e) { var checkBox = sender as CheckBox; var item = checkBox.DataContext as DeckItem; if (item != null && deckGrid.SelectedItems.Contains(item)) { deckGrid.SelectedItems.Remove(item); } }
- 更新XAML复选框事件:
<CheckBox IsChecked="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged}" Name="cbkSelect" Margin="10,0,0,0" Checked="CheckedTest" Unchecked="UncheckedTest"/>
额外注意事项
- 确保DataGrid的
SelectionMode="Extended"和SelectionUnit="FullRow"设置正确(当前代码已配置)。 - 行虚拟化开启时,
ItemContainerGenerator无法获取非可视区域的行容器,通过数据项操作SelectedItems比直接操作UI行更可靠。
内容的提问来源于stack exchange,提问作者nihasmata
相关产品推荐
相关产品推荐

