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

WPF MVVM中实现DataGrid列头与列内复选框联动的方法

嘿,这个双向联动的复选框表头需求,你当前的XAML只能实现表头控制单元格的单向操作,反过来单元格状态变化没法反馈给表头。要实现完整的联动逻辑,我们得结合MVVM模式在ViewModel层处理状态同步,下面是一步步的解决方案:

双向联动复选框表头实现方案

1. 定义行数据的ViewModel

首先给每一行数据创建独立的ViewModel,包含IsChecked属性并实现INotifyPropertyChanged,用来通知UI状态变化:

public class ItemViewModel : INotifyPropertyChanged
{
    private bool _isChecked;
    public bool IsChecked
    {
        get => _isChecked;
        set
        {
            if (_isChecked != value)
            {
                _isChecked = value;
                OnPropertyChanged(nameof(IsChecked));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. 实现集合管理ViewModel

创建一个管理所有行数据的ViewModel,它负责处理表头AllChecked属性和所有行IsChecked的双向联动:

public class MainViewModel : INotifyPropertyChanged
{
    private ObservableCollection<ItemViewModel> _items;
    public ObservableCollection<ItemViewModel> Items
    {
        get => _items;
        set
        {
            if (_items != value)
            {
                // 取消旧集合的事件订阅
                if (_items != null)
                {
                    foreach (var item in _items)
                    {
                        item.PropertyChanged -= Item_PropertyChanged;
                    }
                }

                _items = value;

                // 订阅新集合中每个项的状态变化事件
                if (_items != null)
                {
                    foreach (var item in _items)
                    {
                        item.PropertyChanged += Item_PropertyChanged;
                    }
                }

                OnPropertyChanged(nameof(Items));
                UpdateAllCheckedState();
            }
        }
    }

    private bool _allChecked;
    public bool AllChecked
    {
        get => _allChecked;
        set
        {
            if (_allChecked != value)
            {
                _allChecked = value;
                // 表头状态变化时,同步所有行的复选框状态
                if (_items != null)
                {
                    foreach (var item in _items)
                    {
                        item.IsChecked = value;
                    }
                }
                OnPropertyChanged(nameof(AllChecked));
            }
        }
    }

    private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(ItemViewModel.IsChecked))
        {
            // 任意行复选框变化时,更新表头状态
            UpdateAllCheckedState();
        }
    }

    private void UpdateAllCheckedState()
    {
        if (_items == null || _items.Count == 0)
        {
            AllChecked = false;
            return;
        }

        // 检查所有行是否都被选中
        bool allItemsChecked = _items.All(item => item.IsChecked);
        if (allItemsChecked != _allChecked)
        {
            _allChecked = allItemsChecked;
            OnPropertyChanged(nameof(AllChecked));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    // 构造函数:初始化示例数据
    public MainViewModel()
    {
        Items = new ObservableCollection<ItemViewModel>
        {
            new ItemViewModel(),
            new ItemViewModel(),
            new ItemViewModel()
        };
    }
}

3. 修改XAML绑定逻辑

调整XAML的绑定关系,让表头复选框绑定到集合ViewModel的AllChecked属性,单元格复选框绑定到对应行的IsChecked属性:

<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.Header>
                <CheckBox 
                    x:Name="chbHeader" 
                    IsChecked="{Binding DataContext.AllChecked, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Mode=TwoWay}" />
            </DataGridTemplateColumn.Header>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <!-- 其他业务列可以在这里添加 -->
    </DataGrid.Columns>
</DataGrid>

4. 绑定ViewModel到UI

最后在窗口/页面的构造函数中,把MainViewModel设置为DataContext:

public MainWindow()
{
    InitializeComponent();
    DataContext = new MainViewModel();
}

核心逻辑说明

  • 表头复选框状态变化时,AllChecked的setter会遍历所有行,同步设置IsChecked,实现全选/全不选。
  • 任意一行的复选框状态变化时,会触发UpdateAllCheckedState方法,检查所有行是否都被选中,从而自动更新表头复选框的状态。
  • 使用ObservableCollection确保集合新增/删除行时,UI能自动同步,同时订阅每个行项的PropertyChanged事件监听状态变化。

内容的提问来源于stack exchange,提问作者tweety

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 12:57:38