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

WPF实现分组标题Checkbox批量控制组内所有行状态

WPF MVVM实现DataGrid分组头批量控制开关方案

我采用MVVM模式开发WPF+C#应用,通过DataGrid展示PropertyItem类数据,使用ListCollectionView实现分组功能。目前每行已配置Checkbox,可单独控制单个PropertyItem的启用(On)/禁用状态。现在需要在分组的Expander.Header中添加Checkbox,实现一键批量关闭整组PropertyItem,以下是具体实现方案:

步骤1:完善PropertyItem类(实现属性变更通知)

首先让PropertyItem实现INotifyPropertyChanged接口,确保批量修改On属性后UI能同步更新:

using System.ComponentModel;
using System.Runtime.CompilerServices;

public class PropertyItem : INotifyPropertyChanged
{
    private string _propertyName = string.Empty;
    private string _pset = string.Empty;
    private string _mapping = "";
    private bool _on = true;

    public string PropertyName
    {
        get => _propertyName;
        set
        {
            _propertyName = value;
            OnPropertyChanged();
        }
    }

    public string Pset
    {
        get => _pset;
        set
        {
            _pset = value;
            OnPropertyChanged();
        }
    }

    public string Mapping
    {
        get => _mapping;
        set
        {
            _mapping = value;
            OnPropertyChanged();
        }
    }

    public bool On
    {
        get => _on;
        set
        {
            _on = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

步骤2:在ViewModel中添加批量控制命令

假设你的ViewModel类(如MainViewModel)中已有chosenConceptProperties和_chosenConcept,添加通用RelayCommand实现和批量关闭分组的方法:

using System.Windows.Input;

// 通用RelayCommand实现
public class RelayCommand : ICommand
{
    private readonly Action<object> _execute;
    private readonly Func<object, bool> _canExecute;

    public event EventHandler CanExecuteChanged
    {
        add => CommandManager.RequerySuggested += value;
        remove => CommandManager.RequerySuggested -= value;
    }

    public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
    {
        _execute = execute ?? throw new ArgumentNullException(nameof(execute));
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter) => _canExecute?.Invoke(parameter) ?? true;

    public void Execute(object parameter) => _execute(parameter);
}

// ViewModel核心代码
public class MainViewModel : INotifyPropertyChanged
{
    private EntityConcept _chosenConcept = new EntityConcept();
    private ListCollectionView _chosenConceptProperties;

    public ListCollectionView chosenConceptProperties
    {
        get => _chosenConceptProperties;
        set
        {
            _chosenConceptProperties = value;
            OnPropertyChanged();
        }
    }

    public ICommand BatchTurnOffGroupCommand { get; }

    public MainViewModel()
    {
        // 初始化数据(根据实际业务替换)
        _chosenConcept.propertyList = new ObservableCollection<PropertyItem>();
        chosenConceptProperties = new ListCollectionView(_chosenConcept.propertyList);
        chosenConceptProperties.GroupDescriptions.Add(new PropertyGroupDescription("Pset"));

        // 初始化批量控制命令
        BatchTurnOffGroupCommand = new RelayCommand(BatchTurnOffGroup);
    }

    private void BatchTurnOffGroup(object parameter)
    {
        if (parameter is string psetName)
        {
            // 筛选当前分组下的所有项,批量设置为禁用
            var groupItems = _chosenConcept.propertyList.Where(item => item.Pset == psetName);
            foreach (var item in groupItems)
            {
                item.On = false;
            }
        }
    }

    // ViewModel实现属性变更通知
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

// EntityConcept类完善属性变更通知
public class EntityConcept : INotifyPropertyChanged
{
    private string _name;
    private ObservableCollection<PropertyItem> _propertyList = new ObservableCollection<PropertyItem>();

    public ObservableCollection<PropertyItem> propertyList
    {
        get => _propertyList;
        set
        {
            _propertyList = value;
            OnPropertyChanged();
        }
    }

    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));
    }
}

步骤3:修改XAML,添加分组头Checkbox

在Expander.Header的Grid中添加Checkbox,绑定ViewModel的批量命令并传递分组名称作为参数:

<Window.Resources>
    <CollectionViewSource x:Key="cvsTasks">
        <CollectionViewSource.GroupDescriptions>
            <PropertyGroupDescription PropertyName="Pset"/>
        </CollectionViewSource.GroupDescriptions>
    </CollectionViewSource>
</Window.Resources>
<DataGrid x:Name="propertiesTable"
          ItemsSource="{Binding chosenConceptProperties}"
          Grid.Column="1" 
          Grid.ColumnSpan="3" 
          Grid.Row="3" 
          HorizontalAlignment="Stretch" 
          VerticalAlignment="Stretch" 
          AutoGenerateColumns="False" 
          CanUserAddRows="False"
          Margin="0,25,0,0" CellEditEnding="propertiesTable_CellEditEnding">
    <DataGrid.Columns>
        <DataGridTextColumn Width="10*" MinWidth="250" Header="Property Name" Binding="{Binding PropertyName}" IsReadOnly="True" FontSize="10" />
        <DataGridTextColumn Width="10*" MinWidth="250" Header="Mapping" Binding="{Binding Mapping}" IsReadOnly="False" FontSize="10" />
        <DataGridCheckBoxColumn Width="*" MinWidth="50" Header="On/Off" IsReadOnly="False" Binding="{Binding On}"/>
    </DataGrid.Columns>
    <DataGrid.GroupStyle>
        <GroupStyle>
            <GroupStyle.ContainerStyle>
                <Style TargetType="{x:Type GroupItem}">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type GroupItem}">
                                <Expander x:Name="exp" IsExpanded="True" Background="White" Foreground="Black" BorderThickness="1,1,1,5">
                                    <Expander.Header>
                                        <Grid>
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition Width="10*"/>
                                                <ColumnDefinition Width="10*"/>
                                                <ColumnDefinition Width="*"/>
                                            </Grid.ColumnDefinitions>
                                            <TextBlock Grid.Column="0" Text="{Binding Path=Name}" Foreground="#2a5fa4" FontWeight="Bold"/>
                                            <!-- 新增分组头批量控制Checkbox -->
                                            <CheckBox Grid.Column="2" Content="批量关闭" 
                                                      Command="{Binding DataContext.BatchTurnOffGroupCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}"
                                                      CommandParameter="{Binding Name}"/>
                                        </Grid>
                                    </Expander.Header>
                                    <Expander.Content>
                                        <ItemsPresenter/>
                                    </Expander.Content>
                                </Expander>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </GroupStyle.ContainerStyle>
        </GroupStyle>
    </DataGrid.GroupStyle>
</DataGrid>

关键说明

  • 分组头的DataContext是CollectionViewGroup,因此Checkbox的命令需要通过RelativeSource绑定到DataGrid的DataContext(即ViewModel)。
  • CommandParameter绑定分组的Name(对应Pset字段值),用于在命令中精准筛选目标分组的所有项。
  • 所有涉及UI更新的类均实现INotifyPropertyChanged,确保属性变更能实时同步到界面。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 22:24:13