You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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:

  1. 数据模型改造(假设你的数据项类型是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));
    }
}
  1. 修改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集合:

  1. 修改后台代码:
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);
    }
}
  1. 更新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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 21:36:29