如何在C# WinForms的DataGridView中实现单元格内滚动?
给DataGridView指定列的单元格添加滚动条(仅长内容时显示)
不需要重写整个DataGridView,只需通过自定义单元格/列或动态嵌入带滚动条的TextBox两种方案实现,以下是具体步骤:
方案一:自定义单元格与列(推荐,集成度高)
通过继承DataGridViewTextBoxCell和DataGridViewTextBoxColumn,创建支持滚动条的自定义单元格类型,仅对目标列使用该类型即可。
1. 定义自定义单元格和编辑控件
// 自定义支持滚动的文本单元格 public class DataGridViewScrollableTextBoxCell : DataGridViewTextBoxCell { public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle) { base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle); var txtBox = DataGridView.EditingControl as TextBox; if (txtBox == null) return; txtBox.Multiline = true; txtBox.WordWrap = true; txtBox.BorderStyle = BorderStyle.None; // 根据内容高度判断是否显示垂直滚动条 var textSize = TextRenderer.MeasureText(txtBox.Text, txtBox.Font, new Size(txtBox.Width, int.MaxValue), TextFormatFlags.WordBreak); txtBox.ScrollBars = textSize.Height > txtBox.Height ? ScrollBars.Vertical : ScrollBars.None; } public override Type EditType => typeof(DataGridViewScrollableTextBoxEditingControl); } // 自定义编辑控件,实现IDataGridViewEditingControl接口 public class DataGridViewScrollableTextBoxEditingControl : TextBox, IDataGridViewEditingControl { private DataGridView _dgv; private bool _valueChanged; private int _rowIndex; public DataGridView EditingControlDataGridView { get => _dgv; set => _dgv = value; } public object EditingControlFormattedValue { get => Text; set => Text = value.ToString(); } public int EditingControlRowIndex { get => _rowIndex; set => _rowIndex = value; } public bool EditingControlValueChanged { get => _valueChanged; set => _valueChanged = value; } public Cursor EditingPanelCursor => base.Cursor; public bool RepositionEditingControlOnValueChange => false; public void ApplyCellStyleToEditingControl(DataGridViewCellStyle style) { Font = style.Font; ForeColor = style.ForeColor; BackColor = style.BackColor; } public bool EditingControlWantsInputKey(Keys keyData, bool dgvWantsKey) { // 优先让文本框处理方向键、编辑键等输入 switch (keyData & Keys.KeyCode) { case Keys.Left: case Keys.Right: case Keys.Up: case Keys.Down: case Keys.Home: case Keys.End: case Keys.Delete: case Keys.Back: return true; default: return !dgvWantsKey; } } public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) { return EditingControlFormattedValue; } public void PrepareEditingControlForEdit(bool selectAll) { if (selectAll) SelectAll(); else SelectionStart = Text.Length; } }
2. 定义自定义列
public class DataGridViewScrollableTextBoxColumn : DataGridViewTextBoxColumn { public DataGridViewScrollableTextBoxColumn() { CellTemplate = new DataGridViewScrollableTextBoxCell(); } }
3. 在窗体中使用自定义列
方式一:设计时添加
打开窗体设计器,右键DataGridView → 编辑列,删除目标列后添加DataGridViewScrollableTextBoxColumn,设置列名、表头文本等属性。
方式二:代码动态添加
private void Form_Load(object sender, EventArgs e) { // 移除目标列(示例为索引2的列) dataGridView1.Columns.RemoveAt(2); // 创建并添加自定义滚动列 var scrollColumn = new DataGridViewScrollableTextBoxColumn { Name = "LongContentColumn", HeaderText = "长内容列", Width = 220 }; dataGridView1.Columns.Insert(2, scrollColumn); // 配置单元格换行与行高(可选:固定行高或自动调整) dataGridView1.RowsDefaultCellStyle.WrapMode = DataGridViewTriState.True; // 自动调整行高(若要固定行高,设置dataGridView1.RowTemplate.Height = 100;) dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells; // 添加测试数据 dataGridView1.Rows.Add("测试项1", "测试项2", "这是一段超长文本,包含多行内容,用来验证滚动条的显示逻辑。当文本高度超过单元格高度时,会自动启用垂直滚动条;内容较短时则隐藏滚动条。这是一段超长文本,包含多行内容,用来验证滚动条的显示逻辑。", "测试项4", "测试项5", "测试项6"); }
方案二:动态嵌入TextBox(快速实现)
无需自定义类,通过CellEnter/CellLeave事件动态在目标单元格中添加带滚动条的TextBox,离开单元格时将内容写回单元格。
实现代码
private TextBox _scrollTxtBox; private void dataGridView1_CellEnter(object sender, DataGridViewCellEventArgs e) { // 仅处理目标列(示例为索引2的列) if (e.ColumnIndex != 2 || e.RowIndex < 0) return; // 清理之前的TextBox _scrollTxtBox?.Dispose(); _scrollTxtBox = null; // 获取单元格显示区域 var cellRect = dataGridView1.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, true); // 创建带滚动条的TextBox _scrollTxtBox = new TextBox { Multiline = true, WordWrap = true, BorderStyle = BorderStyle.None, Text = dataGridView1[e.ColumnIndex, e.RowIndex].Value?.ToString() ?? "", Font = dataGridView1.DefaultCellStyle.Font, ForeColor = dataGridView1.DefaultCellStyle.ForeColor, BackColor = dataGridView1.DefaultCellStyle.BackColor, Location = new Point(cellRect.X, cellRect.Y), Size = new Size(cellRect.Width - 2, cellRect.Height - 2) }; // 根据内容高度判断是否显示滚动条 var textSize = TextRenderer.MeasureText(_scrollTxtBox.Text, _scrollTxtBox.Font, new Size(_scrollTxtBox.Width, int.MaxValue), TextFormatFlags.WordBreak); _scrollTxtBox.ScrollBars = textSize.Height > _scrollTxtBox.Height ? ScrollBars.Vertical : ScrollBars.None; dataGridView1.Controls.Add(_scrollTxtBox); _scrollTxtBox.Focus(); } private void dataGridView1_CellLeave(object sender, DataGridViewCellEventArgs e) { if (_scrollTxtBox == null || e.ColumnIndex != 2) return; // 将内容写回单元格 dataGridView1[e.ColumnIndex, e.RowIndex].Value = _scrollTxtBox.Text; dataGridView1.Controls.Remove(_scrollTxtBox); _scrollTxtBox.Dispose(); _scrollTxtBox = null; } // 处理列宽/行高变化时的TextBox尺寸调整 private void dataGridView1_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e) { AdjustScrollTextBoxSize(e.Column.Index); } private void dataGridView1_RowHeightChanged(object sender, DataGridViewRowEventArgs e) { AdjustScrollTextBoxSize(dataGridView1.CurrentCell?.ColumnIndex ?? -1); } private void AdjustScrollTextBoxSize(int columnIndex) { if (_scrollTxtBox == null || columnIndex != 2 || dataGridView1.CurrentCell == null) return; var cellRect = dataGridView1.GetCellDisplayRectangle(columnIndex, dataGridView1.CurrentCell.RowIndex, true); _scrollTxtBox.Size = new Size(cellRect.Width - 2, cellRect.Height - 2); var textSize = TextRenderer.MeasureText(_scrollTxtBox.Text, _scrollTxtBox.Font, new Size(_scrollTxtBox.Width, int.MaxValue), TextFormatFlags.WordBreak); _scrollTxtBox.ScrollBars = textSize.Height > _scrollTxtBox.Height ? ScrollBars.Vertical : ScrollBars.None; }
注意事项
- 若希望固定行高(避免行过高),设置
dataGridView1.RowTemplate.Height = 100;(根据需求调整数值),此时内容超过高度会自动显示滚动条。 - 必须开启单元格换行:
dataGridView1.RowsDefaultCellStyle.WrapMode = DataGridViewTriState.True;,否则文本不会换行,滚动条无法触发。
内容的提问来源于stack exchange,提问作者sadegh
相关产品推荐
相关产品推荐

