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

C# WinForm DataGridView实现单列放编辑删除按钮或合并列头

在C# WinForms DataGridView中实现同一列放置Edit/Delete按钮

方法一:自定义单元格列(推荐)

直接创建包含两个按钮的自定义DataGridView列,单元格原生支持双按钮布局,逻辑更稳定。

1. 自定义单元格类

继承DataGridViewCell,重写绘制与点击判断逻辑:

public class EditDeleteCell : DataGridViewCell
{
    private Rectangle _editButtonRect;
    private Rectangle _deleteButtonRect;
    private const int ButtonWidth = 60;
    private const int ButtonHeight = 22;

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

        // 计算双按钮居中位置
        int totalWidth = ButtonWidth * 2 + 5;
        int startX = cellBounds.Left + (cellBounds.Width - totalWidth) / 2;
        int startY = cellBounds.Top + (cellBounds.Height - ButtonHeight) / 2;

        _editButtonRect = new Rectangle(startX, startY, ButtonWidth, ButtonHeight);
        _deleteButtonRect = new Rectangle(startX + ButtonWidth + 5, startY, ButtonWidth, ButtonHeight);

        // 绘制按钮样式
        ButtonRenderer.DrawButton(graphics, _editButtonRect, "Edit", DataGridView.Font, false, PushButtonState.Normal);
        ButtonRenderer.DrawButton(graphics, _deleteButtonRect, "Delete", DataGridView.Font, false, PushButtonState.Normal);
    }

    protected override void OnMouseClick(DataGridViewCellMouseEventArgs e)
    {
        base.OnMouseClick(e);
        if (e.RowIndex < 0) return;

        // 判断点击目标并触发对应事件
        if (_editButtonRect.Contains(e.Location))
        {
            ((EditDeleteColumn)OwningColumn).OnEditClicked(new DataGridViewCellEventArgs(e.ColumnIndex, e.RowIndex));
        }
        else if (_deleteButtonRect.Contains(e.Location))
        {
            ((EditDeleteColumn)OwningColumn).OnDeleteClicked(new DataGridViewCellEventArgs(e.ColumnIndex, e.RowIndex));
        }
    }
}

2. 自定义列类

关联自定义单元格,暴露按钮点击事件:

public class EditDeleteColumn : DataGridViewColumn
{
    public event EventHandler<DataGridViewCellEventArgs> EditClicked;
    public event EventHandler<DataGridViewCellEventArgs> DeleteClicked;

    public EditDeleteColumn() : base(new EditDeleteCell())
    {
        Width = 130;
        HeaderText = "操作";
    }

    public override DataGridViewCell CellTemplate
    {
        get => base.CellTemplate;
        set
        {
            if (value != null && !(value is EditDeleteCell))
                throw new InvalidCastException("必须使用EditDeleteCell类型");
            base.CellTemplate = value;
        }
    }

    internal void OnEditClicked(DataGridViewCellEventArgs e)
    {
        EditClicked?.Invoke(this, e);
    }

    internal void OnDeleteClicked(DataGridViewCellEventArgs e)
    {
        DeleteClicked?.Invoke(this, e);
    }
}

3. 窗体中使用

添加自定义列并绑定事件:

public Form1()
{
    InitializeComponent();

    // 添加自定义操作列
    var editDeleteCol = new EditDeleteColumn();
    dataGridView1.Columns.Add(editDeleteCol);

    // 绑定按钮点击逻辑
    editDeleteCol.EditClicked += (s, e) =>
    {
        var row = dataGridView1.Rows[e.RowIndex];
        MessageBox.Show($"编辑行:{row.Cells[0].Value}");
    };
    editDeleteCol.DeleteClicked += (s, e) =>
    {
        if (MessageBox.Show("确定删除该行?", "提示", MessageBoxButtons.YesNo) == DialogResult.Yes)
        {
            dataGridView1.Rows.RemoveAt(e.RowIndex);
        }
    };

    // 示例数据
    dataGridView1.Rows.Add("张三", "25");
    dataGridView1.Rows.Add("李四", "30");
}

方法二:合并列头+无边框按钮列

通过合并两个按钮列的表头、隐藏边框,模拟同一列效果:

1. 添加两个按钮列

// Edit列
var editCol = new DataGridViewButtonColumn();
editCol.Name = "EditCol";
editCol.Text = "Edit";
editCol.UseColumnTextForButtonValue = true;
editCol.Width = 60;
editCol.HeaderText = "";

// Delete列
var deleteCol = new DataGridViewButtonColumn();
deleteCol.Name = "DeleteCol";
deleteCol.Text = "Delete";
deleteCol.UseColumnTextForButtonValue = true;
deleteCol.Width = 60;
deleteCol.HeaderText = "";

dataGridView1.Columns.Add(editCol);
dataGridView1.Columns.Add(deleteCol);

2. 重写表头绘制

在DataGridView的Paint事件中绘制合并表头:

private void dataGridView1_Paint(object sender, PaintEventArgs e)
{
    var editCol = dataGridView1.Columns["EditCol"];
    var deleteCol = dataGridView1.Columns["DeleteCol"];
    if (editCol == null || deleteCol == null) return;

    // 计算合并后的表头区域
    Rectangle mergeRect = new Rectangle(
        editCol.HeaderCell.ContentBounds.Left,
        editCol.HeaderCell.ContentBounds.Top,
        editCol.Width + deleteCol.Width,
        editCol.HeaderCell.ContentBounds.Height
    );

    // 绘制合并表头文本
    StringFormat sf = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
    var headerStyle = dataGridView1.ColumnHeadersDefaultCellStyle;
    e.Graphics.FillRectangle(new SolidBrush(headerStyle.BackColor), mergeRect);
    e.Graphics.DrawString("操作", headerStyle.Font, new SolidBrush(headerStyle.ForeColor), mergeRect, sf);

    // 隐藏原始列头文本
    editCol.HeaderCell.Style.ForeColor = headerStyle.BackColor;
    deleteCol.HeaderCell.Style.ForeColor = headerStyle.BackColor;
}

3. 隐藏列边框

让两个按钮列视觉上合并:

editCol.DefaultCellStyle.BorderWidth = 0;
deleteCol.DefaultCellStyle.BorderWidth = 0;
editCol.AdvancedBorderStyle.Right = DataGridViewAdvancedCellBorderStyle.None;
deleteCol.AdvancedBorderStyle.Left = DataGridViewAdvancedCellBorderStyle.None;

4. 绑定点击事件

在CellContentClick事件中处理按钮逻辑:

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
    if (e.RowIndex < 0) return;

    if (dataGridView1.Columns[e.ColumnIndex].Name == "EditCol")
    {
        var row = dataGridView1.Rows[e.RowIndex];
        MessageBox.Show($"编辑行:{row.Cells[0].Value}");
    }
    else if (dataGridView1.Columns[e.ColumnIndex].Name == "DeleteCol")
    {
        if (MessageBox.Show("确定删除该行?", "提示", MessageBoxButtons.YesNo) == DialogResult.Yes)
        {
            dataGridView1.Rows.RemoveAt(e.RowIndex);
        }
    }
}

注意:方法二需在ColumnWidthChanged事件中调用dataGridView1.Invalidate(),确保列宽变化时表头重绘。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 07:08:18