如何在C#中实现DataGrid复选框全选/全不选功能
实现全选/全不选功能的完整方案
首先得先修正你的WorkStep类——现有代码用了静态事件,这不是WPF数据绑定的标准做法,会导致所有实例共享同一个事件,容易引发意外问题。我们先让它正确实现INotifyPropertyChanged接口:
public class WorkStep : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private bool isChecked; public string Name { get; } public WorkStep(string name) { Name = name; IsChecked = true; } public WorkStep(string name, bool isChecked) { Name = name; IsChecked = isChecked; } public bool IsChecked { get => isChecked; set { if (isChecked != value) { isChecked = value; OnPropertyChanged(nameof(IsChecked)); } } } private void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
接下来,假设你有一个管理WorkStep集合的ViewModel(比如MainViewModel),我们要在这个类里添加全选控制逻辑,同时处理集合项的状态联动:
public class MainViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private ObservableCollection<WorkStep> _workSteps; private bool? _allChecked; // 用可空布尔值支持"部分选中"的不确定状态 public ObservableCollection<WorkStep> WorkSteps { get => _workSteps; set { if (_workSteps != value) { // 移除旧集合的事件监听 if (_workSteps != null) { foreach (var step in _workSteps) step.PropertyChanged -= WorkStep_PropertyChanged; } _workSteps = value; // 给新集合的每个项添加事件监听 if (_workSteps != null) { foreach (var step in _workSteps) step.PropertyChanged += WorkStep_PropertyChanged; } OnPropertyChanged(nameof(WorkSteps)); UpdateAllCheckedState(); } } } public bool? AllChecked { get => _allChecked; set { if (_allChecked != value) { _allChecked = value; OnPropertyChanged(nameof(AllChecked)); // 同步更新所有项的选中状态 if (value.HasValue && WorkSteps != null) { foreach (var step in WorkSteps) step.IsChecked = value.Value; } } } } // 监听单个项的选中状态变化,更新全选框状态 private void WorkStep_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(WorkStep.IsChecked)) { UpdateAllCheckedState(); } } // 根据集合项的状态,计算全选框应该显示的状态 private void UpdateAllCheckedState() { if (WorkSteps == null || WorkSteps.Count == 0) { _allChecked = false; } else { var allChecked = WorkSteps.All(s => s.IsChecked); var noneChecked = WorkSteps.All(s => !s.IsChecked); // 全选→true,全不选→false,部分选→null(对应CheckBox的不确定状态) _allChecked = allChecked ? true : noneChecked ? false : null; } OnPropertyChanged(nameof(AllChecked)); } private void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } // 示例构造函数,初始化测试数据 public MainViewModel() { WorkSteps = new ObservableCollection<WorkStep> { new WorkStep("需求分析"), new WorkStep("原型设计"), new WorkStep("开发编码", false), new WorkStep("测试验收") }; } }
最后修改你的XAML代码,在DataGrid的表头添加全选CheckBox,并绑定到ViewModel的AllChecked属性:
<DataGrid ItemsSource="{Binding WorkSteps}" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTemplateColumn> <!-- 表头的全选CheckBox --> <DataGridTemplateColumn.HeaderTemplate> <DataTemplate> <CheckBox IsChecked="{Binding DataContext.AllChecked, RelativeSource={RelativeSource AncestorType=DataGrid}, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"/> </DataTemplate> </DataGridTemplateColumn.HeaderTemplate> <!-- 单元格的单个CheckBox --> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <CheckBox IsChecked="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <!-- 显示步骤名称的列 --> <DataGridTextColumn Header="步骤名称" Binding="{Binding Name}" Width="*"/> </DataGrid.Columns> </DataGrid>
别忘了把ViewModel设置为窗口的DataContext(比如在窗口构造函数里):
public MainWindow() { InitializeComponent(); DataContext = new MainViewModel(); }
核心逻辑说明:
- 全选CheckBox支持三种状态:选中(全选所有项)、未选中(取消所有项)、不确定(部分项选中),用户体验更友好。
- 单个项的选中状态变化会实时同步到全选框;全选框的状态变化也会同步到所有项,实现双向联动。
- 严格遵循WPF的MVVM模式,数据和UI完全解耦,代码可维护性更强。
内容的提问来源于stack exchange,提问作者Dragan
相关产品推荐
相关产品推荐

