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
相关产品推荐
相关产品推荐

