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

WPF C#:如何在DataGrid单元格中定义包含数量不定CheckBox控件的列

实现DataGrid单元格内动态数量CheckBox的方案

嘿,这个需求我之前做过好几次,给你分享两个主流框架的实现思路,核心都是让每行数据携带自己的CheckBox选项集合,再通过模板或自定义控件动态渲染出来~


WPF 版本(推荐,数据绑定更简洁)

1. 先定义选项数据模型

首先要个小类来存每个CheckBox的状态和显示文本,记得实现INotifyPropertyChanged保证数据和UI同步:

public class CheckBoxItem : INotifyPropertyChanged
{
    private bool _isChecked;
    private string _label;

    public bool IsChecked
    {
        get => _isChecked;
        set { _isChecked = value; OnPropertyChanged(); }
    }

    public string Label
    {
        get => _label;
        set { _label = value; OnPropertyChanged(); }
    }

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

2. 定义DataGrid的行数据模型

你的主数据类里要加一个List<CheckBoxItem>属性,用来存储当前行对应的所有CheckBox选项:

public class GridRowData : INotifyPropertyChanged
{
    // 这里放你原来的行属性,比如ID、名称之类的
    public string RowId { get; set; }
    
    // 关键:每个行自己的CheckBox集合
    private List<CheckBoxItem> _checkBoxOptions;
    public List<CheckBoxItem> CheckBoxOptions
    {
        get => _checkBoxOptions;
        set { _checkBoxOptions = value; OnPropertyChanged(); }
    }

    // 同样实现INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

3. XAML里配置动态列

用DataGridTemplateColumn结合ItemsControl,就能自动根据绑定的集合生成CheckBox:

<DataGrid x:Name="MyDataGrid" AutoGenerateColumns="False" Margin="10">
    <DataGrid.Columns>
        <!-- 常规文本列示例 -->
        <DataGridTextColumn Header="行ID" Binding="{Binding RowId}" Width="100"/>
        
        <!-- 动态CheckBox列 -->
        <DataGridTemplateColumn Header="自定义选项">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <!-- 用ItemsControl遍历当前行的CheckBoxOptions集合 -->
                    <ItemsControl ItemsSource="{Binding CheckBoxOptions}">
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal" Margin="2">
                                    <CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" />
                                    <TextBlock Text="{Binding Label}" Margin="4,0,0,0"/>
                                </StackPanel>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                        <!-- 可以设置ItemsPanel让CheckBox横向排列,默认是纵向 -->
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <WrapPanel />
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                    </ItemsControl>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

4. 填充数据源

后台给每行的CheckBoxOptions赋值不同的集合,就能实现每个单元格CheckBox数量/文本不一样:

var dataSource = new List<GridRowData>
{
    new GridRowData
    {
        RowId = "Row1",
        CheckBoxOptions = new List<CheckBoxItem>
        {
            new CheckBoxItem { Label = "选项A", IsChecked = true },
            new CheckBoxItem { Label = "选项B" }
        }
    },
    new GridRowData
    {
        RowId = "Row2",
        CheckBoxOptions = new List<CheckBoxItem>
        {
            new CheckBoxItem { Label = "选项X" },
            new CheckBoxItem { Label = "选项Y" },
            new CheckBoxItem { Label = "选项Z", IsChecked = true }
        }
    }
};

MyDataGrid.ItemsSource = dataSource;

WinForms 版本(DataGridView)

WinForms没有WPF那么灵活的绑定,得自定义单元格来处理绘制和编辑:

1. 同样先定义选项模型

public class CheckBoxItem
{
    public bool IsChecked { get; set; }
    public string Label { get; set; }
}

2. 自定义CheckBox列表单元格

public class CheckBoxListCell : DataGridViewTextBoxCell
{
    private FlowLayoutPanel _panel;
    private List<CheckBox> _checkBoxes = new List<CheckBox>();

    // 存储当前单元格的CheckBox选项
    public List<CheckBoxItem> CheckBoxItems { get; set; }

    protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
    {
        // 先绘制单元格背景
        base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);

        // 初始化承载CheckBox的FlowLayoutPanel
        if (_panel == null)
        {
            _panel = new FlowLayoutPanel
            {
                Size = cellBounds.Size,
                Padding = new Padding(2),
                AutoScroll = true
            };
        }

        // 清空旧控件,添加新的CheckBox
        _panel.Controls.Clear();
        _checkBoxes.Clear();
        if (CheckBoxItems != null)
        {
            foreach (var item in CheckBoxItems)
            {
                var cb = new CheckBox
                {
                    Text = item.Label,
                    Checked = item.IsChecked,
                    AutoSize = true
                };
                // 同步CheckBox状态到数据模型
                cb.CheckedChanged += (s, e) => item.IsChecked = cb.Checked;
                _panel.Controls.Add(cb);
                _checkBoxes.Add(cb);
            }
        }

        // 把Panel绘制到单元格里
        _panel.Size = cellBounds.Size;
        using (var bmp = new Bitmap(cellBounds.Width, cellBounds.Height))
        {
            _panel.DrawToBitmap(bmp, new Rectangle(0, 0, cellBounds.Width, cellBounds.Height));
            graphics.DrawImage(bmp, cellBounds.Location);
        }
    }

    // 处理编辑状态,让用户能点击CheckBox
    public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
    {
        base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
        var host = DataGridView.EditingControl as DataGridViewEditingControlHost;
        if (host == null)
        {
            host = new DataGridViewEditingControlHost(_panel);
            DataGridView.EditingControl = host;
        }
    }

    public override Type EditType => typeof(DataGridViewEditingControlHost);
}

3. 自定义列类

public class CheckBoxListColumn : DataGridViewColumn
{
    public CheckBoxListColumn() : base(new CheckBoxListCell()) { }

    public override DataGridViewCell CellTemplate
    {
        get => base.CellTemplate;
        set
        {
            if (value != null && !(value is CheckBoxListCell))
                throw new InvalidCastException("单元格必须是CheckBoxListCell类型");
            base.CellTemplate = value;
        }
    }
}

4. 在窗体里使用

// 初始化DataGridView
dataGridView1.AutoGenerateColumns = false;
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "行ID", DataPropertyName = "RowId" });
dataGridView1.Columns.Add(new CheckBoxListColumn { HeaderText = "自定义选项" });

// 添加行数据
var row1 = new DataGridViewRow();
row1.CreateCells(dataGridView1);
row1.Cells[0].Value = "Row1";
((CheckBoxListCell)row1.Cells[1]).CheckBoxItems = new List<CheckBoxItem>
{
    new CheckBoxItem { Label = "选项A", IsChecked = true },
    new CheckBoxItem { Label = "选项B" }
};
dataGridView1.Rows.Add(row1);

var row2 = new DataGridViewRow();
row2.CreateCells(dataGridView1);
row2.Cells[0].Value = "Row2";
((CheckBoxListCell)row2.Cells[1]).CheckBoxItems = new List<CheckBoxItem>
{
    new CheckBoxItem { Label = "选项X" },
    new CheckBoxItem { Label = "选项Y" },
    new CheckBoxItem { Label = "选项Z", IsChecked = true }
};
dataGridView1.Rows.Add(row2);

核心要点总结

  • 不管哪种框架,核心都是让每行数据拥有独立的CheckBox选项集合,这样才能实现不同单元格的动态数量
  • WPF靠数据绑定+模板实现,代码更简洁易维护;WinForms需要自定义单元格处理绘制和交互
  • 记得同步CheckBox的状态到数据模型,这样后续才能获取用户选择的结果

内容的提问来源于stack exchange,提问作者pl.lepko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 08:32:51