将行号列添加到绑定到 DataTable 的 DataGridView
Add row number column to DataGridView bound to DataTable
在 ADO.NET 中,我使用 DataAdapter.Fill (..)
调用用数据库中的值填充 DataTable。然后我将 DataTable 绑定到 DataGrid 以允许滚动浏览所有值、编辑并将更改更新回数据库。所有标准的东西。我对所有这些都使用 Visual Studio Windows 表单向导,因为它非常标准。
但现在我想显示一个左侧列(不是数据库行的一部分)来对显示在 DataGrid 中的行进行编号。我仍然希望按原样保留绑定的行数据,并自动更新回数据库等。显然,我不能用巫师做到这一点。
方法一
如果我手动执行此操作,我会更改 DataTable 加载查询以包含一个虚拟整数列,以将所需的行号列注入返回的 table:
SELECT ‘’ as Num, * from MyTable
然后我将在将 DataTable 绑定到网格之前以编程方式将行号插入该字段,这将根据需要显示行号。我希望 DataTable 的自动更新代码会忽略网格中的额外列。
方法二
另一种可能的方法是在 DataGrid 绑定到 DataSource(我的 DataTable)之后以编程方式将新列添加到 DataGrid。然后我会在显示网格之前用行号填充新列。
问题
但在我放弃方便的向导并为所有事情进行手动工作之前,我想问一下是否有一种标准的方法来做这类事情。我不敢相信我是第一个想要在网格显示中使用行号(不是数据库行的一部分)的人。
我在这里和其他各种论坛上搜索过想法,但是 none 讨论了当您将新列注入 table 加载查询(方法 1)时更新代码会发生什么) 或将 DataGrid 绑定到数据源(方法 2)后进入网格。
我什至想过使用来自两个不同绑定源的两个相邻的网格控件。但是在滚动期间保持它们同步所需的代码似乎需要更多工作。
谁能指出解决此问题的最佳方法或提供代码片段?我同意进入表单设计器生成的代码以将列添加到绑定的 DataGrid,但我在尝试查找和理解将更改更新回数据库的更新部分时迷失了方向。谢谢。
参见:DataGridViewRow.HeaderCell Property – TnTinMn
TnTinMn 提供了最简单的答案来实现我的目标。我在这里复制了他的评论,以便将其标记为已回答的问题。
加载网格后,只需沿着行向下走,并为行左端的 "header cell" 分配行标签(行号)。好的部分是行号是网格中的标签,而不是网格中未绑定数据的列。
有一些不错的选项,它们不会干扰数据的查询或结构,并且仅基于 GUI 逻辑:
- 使用
RowPostPaint
事件在RowHeader上绘制行号
- 使用行
RowPrePaint
event to assign Row Number to HeaderCell
- 正在创建一个新的
DataGridViewRowNumberColumn
以显示行号
使用RowPostPaint事件在RowHeader上绘制行号
您可以处理 RowPostPaint
并在 header 单元格中绘制行号。下面的一段代码显示了一个简单的逻辑:
private void dataGridView1_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
{
var g = (DataGridView)sender;
var r = new Rectangle(e.RowBounds.Left, e.RowBounds.Top,
g.RowHeadersWidth, e.RowBounds.Height);
TextRenderer.DrawText(e.Graphics, $"{e.RowIndex + 1}",
g.RowHeadersDefaultCellStyle.Font, r, g.RowHeadersDefaultCellStyle.ForeColor);
}
以上代码足够好,但是您可能希望通过将 datagridview 单元格对齐映射到文本格式标志来增强逻辑,例如 this method. You may also want to put the logic inside a custom DataGridView
and override OnRowPostPaint
and also set DoubleBuffered
属性 如果派生 DataGridView
到 true
。
使用 RowPrePaint 事件将行号分配给行的 HeaderCell
如果您将字符串值分配给 header 单元格的 Value
属性,它将显示在行 header 上。
您在循环中赋值,在这种情况下您需要处理 RowAdded
和 RowRemoved
事件以及 re-assign 行号。更好的解决方案是使用 RowPrePaint
并检查 header 单元格的值是否不正确,然后更正它:
private void dataGridView1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
var g = (DataGridView)sender;
if (e.RowIndex > -1 && $"{g.Rows[e.RowIndex].HeaderCell.Value}" != $"{e.RowIndex + 1}")
{
g.Rows[e.RowIndex].HeaderCell.Value = $"{e.RowIndex + 1}";
}
}
正在创建一个新的 DataGridViewRowNumberColumn
以显示行号
第二个选项是创建一个新的可重复使用的列类型来显示行号。您可以像使用任何其他列类型一样使用此列类型。您可以在 design-time 或 run-time.
添加列
using System.ComponentModel;
using System.Windows.Forms;
public class DataGridViewRowNumberColumn : DataGridViewColumn
{
public DataGridViewRowNumberColumn() : base()
{
this.CellTemplate = new DataGridViewRowNumberCell();
this.Width = 40;
this.SortMode = DataGridViewColumnSortMode.NotSortable;
}
[Browsable(false)]
[DefaultValue(true)]
public override bool ReadOnly
{
get { return true; }
set { base.ReadOnly = true; }
}
}
public class DataGridViewRowNumberCell : DataGridViewTextBoxCell
{
protected override void Paint(System.Drawing.Graphics graphics,
System.Drawing.Rectangle clipBounds, System.Drawing.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);
}
protected override object GetValue(int rowIndex)
{
return rowIndex + 1;
}
protected override bool SetValue(int rowIndex, object value)
{
return base.SetValue(rowIndex, rowIndex + 1);
}
}
在 ADO.NET 中,我使用 DataAdapter.Fill (..)
调用用数据库中的值填充 DataTable。然后我将 DataTable 绑定到 DataGrid 以允许滚动浏览所有值、编辑并将更改更新回数据库。所有标准的东西。我对所有这些都使用 Visual Studio Windows 表单向导,因为它非常标准。
但现在我想显示一个左侧列(不是数据库行的一部分)来对显示在 DataGrid 中的行进行编号。我仍然希望按原样保留绑定的行数据,并自动更新回数据库等。显然,我不能用巫师做到这一点。
方法一
如果我手动执行此操作,我会更改 DataTable 加载查询以包含一个虚拟整数列,以将所需的行号列注入返回的 table:
SELECT ‘’ as Num, * from MyTable
然后我将在将 DataTable 绑定到网格之前以编程方式将行号插入该字段,这将根据需要显示行号。我希望 DataTable 的自动更新代码会忽略网格中的额外列。
方法二
另一种可能的方法是在 DataGrid 绑定到 DataSource(我的 DataTable)之后以编程方式将新列添加到 DataGrid。然后我会在显示网格之前用行号填充新列。
问题
但在我放弃方便的向导并为所有事情进行手动工作之前,我想问一下是否有一种标准的方法来做这类事情。我不敢相信我是第一个想要在网格显示中使用行号(不是数据库行的一部分)的人。
我在这里和其他各种论坛上搜索过想法,但是 none 讨论了当您将新列注入 table 加载查询(方法 1)时更新代码会发生什么) 或将 DataGrid 绑定到数据源(方法 2)后进入网格。
我什至想过使用来自两个不同绑定源的两个相邻的网格控件。但是在滚动期间保持它们同步所需的代码似乎需要更多工作。
谁能指出解决此问题的最佳方法或提供代码片段?我同意进入表单设计器生成的代码以将列添加到绑定的 DataGrid,但我在尝试查找和理解将更改更新回数据库的更新部分时迷失了方向。谢谢。
参见:DataGridViewRow.HeaderCell Property – TnTinMn
TnTinMn 提供了最简单的答案来实现我的目标。我在这里复制了他的评论,以便将其标记为已回答的问题。
加载网格后,只需沿着行向下走,并为行左端的 "header cell" 分配行标签(行号)。好的部分是行号是网格中的标签,而不是网格中未绑定数据的列。
有一些不错的选项,它们不会干扰数据的查询或结构,并且仅基于 GUI 逻辑:
- 使用
RowPostPaint
事件在RowHeader上绘制行号 - 使用行
RowPrePaint
event to assign Row Number toHeaderCell
- 正在创建一个新的
DataGridViewRowNumberColumn
以显示行号
使用RowPostPaint事件在RowHeader上绘制行号
您可以处理 RowPostPaint
并在 header 单元格中绘制行号。下面的一段代码显示了一个简单的逻辑:
private void dataGridView1_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
{
var g = (DataGridView)sender;
var r = new Rectangle(e.RowBounds.Left, e.RowBounds.Top,
g.RowHeadersWidth, e.RowBounds.Height);
TextRenderer.DrawText(e.Graphics, $"{e.RowIndex + 1}",
g.RowHeadersDefaultCellStyle.Font, r, g.RowHeadersDefaultCellStyle.ForeColor);
}
以上代码足够好,但是您可能希望通过将 datagridview 单元格对齐映射到文本格式标志来增强逻辑,例如 this method. You may also want to put the logic inside a custom DataGridView
and override OnRowPostPaint
and also set DoubleBuffered
属性 如果派生 DataGridView
到 true
。
使用 RowPrePaint 事件将行号分配给行的 HeaderCell
如果您将字符串值分配给 header 单元格的 Value
属性,它将显示在行 header 上。
您在循环中赋值,在这种情况下您需要处理 RowAdded
和 RowRemoved
事件以及 re-assign 行号。更好的解决方案是使用 RowPrePaint
并检查 header 单元格的值是否不正确,然后更正它:
private void dataGridView1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
var g = (DataGridView)sender;
if (e.RowIndex > -1 && $"{g.Rows[e.RowIndex].HeaderCell.Value}" != $"{e.RowIndex + 1}")
{
g.Rows[e.RowIndex].HeaderCell.Value = $"{e.RowIndex + 1}";
}
}
正在创建一个新的 DataGridViewRowNumberColumn
以显示行号
第二个选项是创建一个新的可重复使用的列类型来显示行号。您可以像使用任何其他列类型一样使用此列类型。您可以在 design-time 或 run-time.
添加列using System.ComponentModel;
using System.Windows.Forms;
public class DataGridViewRowNumberColumn : DataGridViewColumn
{
public DataGridViewRowNumberColumn() : base()
{
this.CellTemplate = new DataGridViewRowNumberCell();
this.Width = 40;
this.SortMode = DataGridViewColumnSortMode.NotSortable;
}
[Browsable(false)]
[DefaultValue(true)]
public override bool ReadOnly
{
get { return true; }
set { base.ReadOnly = true; }
}
}
public class DataGridViewRowNumberCell : DataGridViewTextBoxCell
{
protected override void Paint(System.Drawing.Graphics graphics,
System.Drawing.Rectangle clipBounds, System.Drawing.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);
}
protected override object GetValue(int rowIndex)
{
return rowIndex + 1;
}
protected override bool SetValue(int rowIndex, object value)
{
return base.SetValue(rowIndex, rowIndex + 1);
}
}