Datagridview rowsadded 事件在 bindsource 完成之前触发
Datagridview rowsadded event fires before bindsource completed
首先我有:
我得到了一个 datagridview 和 bindsource(目前我自己的数据表来自 sql-call)。绑定源有多个列,但其中一个是我的数据的特定“位置”列。
我想做的事情:
当我将绑定源设置为 datagridview 时,我想更改具有指定“位置”的行的颜色。
我做了什么:
我认为创建一个 RowsAdded 事件并检查添加行的“位置”列是否等于我指定的位置就足够了。基于此,我会更改行的背景色。
代码是这样的:
private void setBindSource(BindingSource bindSource)
{
gridview.DataSource = bindSource;
gridview.EndEdit();
bindSource.EndEdit();
}
private void gridView_RowsAdded(object sender, System.Windows.Forms.DataGridViewRowsAddedEventArgs e)
{
if (e.RowIndex == -1 || e.RowCount == 0)
{
return;
}
for (int index = e.RowIndex; index <= e.RowIndex + e.RowCount - 1; index++)
{
DataGridView dgv = sender as DataGridView;
DataGridViewRow row = dgv.Rows[index];
if ((Int32)row.Cells["position"].Value == specificPosition)
row.DefaultCellStyle.BackColor = Color.Green;
}
}
我面临的问题:
rowsadded 事件按预期触发(在 gridview.DataSource = bindSource;)。但是该行本身没有任何数据(使用的数据表显示了预期的数据)。所以它显然会抛出错误,它找不到指定的列“位置”。我假设 gridview 还没有完全初始化?
添加行后如何更改行的颜色?
当行的背景颜色取决于特定的单元格值时,在“更改”行颜色时应牢记一些事项。
测试特定单元格值和更改行颜色的代码所在的“位置”可以在许多不同的网格事件中完成,并且所有事件(基本上)都会完成相同的事情。然而,做一些简单的测试来帮助您确定您选择的“网格事件”是否“真的”是您需要或应该使用的可能是有益的。
例如,按照建议,您可以订阅网格 CellFormatting
事件来执行您描述的操作,它将按预期工作。但是,使用此事件会产生一个微妙但可能存在的问题。对于初学者来说,几乎所有的网格“格式化”事件都会触发很多次。
如果用户只是将光标移到网格上,则将触发格式化事件。因此,如果光标正好移到目标单元格上,就会执行代码。这可能是可以接受的;但是,从这里可以清楚地看出,检查单元格的值确实是不必要的,因为单元格的值没有改变。用户只需将光标移动到目标单元格上。
如前所述,这可能是可以接受的,但是,如果这种不必要的事件调用混合在一起,不难看出这种情况的许多组合会影响 UI 的性能并且用户可能会遇到缓慢的 UI.
这里的主要思想是……不要将您的代码放在一个会被不必要地触发的事件中,这是一个很好的例子。它可能有效,但代码正在“创建”额外和不必要的执行步骤。
鉴于此,您尝试连接网格 RowsAdded
事件可能会奏效。但是,正如您所指出的,当数据“最初”加载时以及用户手动添加新行或代码添加新行时,似乎需要做一些不同的事情。当数据“初始”加载时,您认为某些单元格可能尚未初始化是正确的。至少你的代码正在查看的单元格。
这可以解决,但是,使用 RowsAdded
事件会遗漏另一个问题……
_“what if the user CHANGES a cells value of a ‘’position’’ cell?”
在这种情况下不会触发新行事件。如果用户将“位置”单元格更改为 specifiedPosition
的值,则该行的背景颜色将不会更改。
考虑到所有这些,为了提供帮助,最好将我们想要代码的“时间”指向 运行。据我所知,这将是“当”位置列中的单元格中的值发生变化时。因此,我建议您订阅 grids CellValueChanged
活动。如果“更改”的单元格是“位置”单元格,则测试单元格值并相应地为行着色。
这将最大限度地减少对代码的不必要调用次数,并将解决前面描述的用户“更改”单元格值时出现的问题。当“用户”添加新行时,这也将起作用。不幸的是,当最初加载数据或通过代码添加新行时,不会触发此事件。
鉴于此,除了在代码中为新添加的行设置正确的行颜色之外,还有一种可能的解决方案是在网格最初加载数据后为行着色,一些小方法可能会派上用场。
第一种方法只是根据“位置”单元格的值为给定的一 (1) 行着色。这假设给定的行不是 null
并且位置列存在并且它是有效的 int.
private void ColorRow(DataGridViewRow row) {
if ((int)row.Cells["position"].Value == specificPosition) {
row.DefaultCellStyle.BackColor = Color.LightGreen;
}
else {
row.DefaultCellStyle.BackColor = Color.White;
}
}
我们可以在网格 CellValueChanged
事件中使用 ColorRow
方法来为特定行着色。此外,在表单加载事件中,在数据初始设置到网格中之后,我们可以调用一个附加方法,该方法简单地循环遍历网格的所有行并调用上面的 ColorRow
方法。这个 ColorSpecificRows
方法可能看起来像……
private void ColorSpecificRows() {
foreach (DataGridViewRow row in gridView.Rows) {
if (!row.IsNewRow) {
ColorRow(row);
}
}
}
接下来,剩下的就是订阅网格 CellValueChanged
事件,它可能看起来像……
private void gridView_CellValueChanged(object sender, DataGridViewCellEventArgs e) {
ColorRow(gridView.Rows[e.RowIndex]);
}
为了帮助测试这个,下面是一个完整的例子。创建一个新的 win 表单解决方案,在表单中添加一个 DataGridView
和一个 Button
。该按钮用于演示以编程方式添加行。
DataTable GridTable;
BindingSource GridBS;
Random rand = new Random();
int specificPosition = 2;
int formattingCount = 0;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
GridTable = GetTable();
FillTable(GridTable);
GridBS = new BindingSource(GridTable, null);
gridView.DataSource = GridBS;
ColorSpecificRows();
}
private DataTable GetTable() {
DataTable dt = new DataTable();
dt.Columns.Add("Col0", typeof(string));
dt.Columns.Add("position", typeof(int));
dt.Columns.Add("Col2", typeof(string));
return dt;
}
private void FillTable(DataTable dt) {
for (int i = 0; i < 10; i++) {
dt.Rows.Add("C0R" + i, rand.Next(1, 4), "C2R" + i);
}
}
private void button1_Click(object sender, EventArgs e) {
GridTable.Rows.Add("new0", 2, "new0");
GridTable.Rows.Add("new1", 3, "new0");
GridTable.Rows.Add("new2", 2, "new0");
ColorSpecificRows();
}
最后,出于测试目的,您可以连接网格 CellFormatting
事件以演示调用该偶数的频率。
private void gridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) {
Debug.WriteLine("CellFormatting - Enter -- FormattingCount: " + ++formattingCount);
// code to change row color
Debug.WriteLine("CellFormatting - Leave");
}
我希望这是有道理的。
首先我有:
我得到了一个 datagridview 和 bindsource(目前我自己的数据表来自 sql-call)。绑定源有多个列,但其中一个是我的数据的特定“位置”列。
我想做的事情:
当我将绑定源设置为 datagridview 时,我想更改具有指定“位置”的行的颜色。
我做了什么:
我认为创建一个 RowsAdded 事件并检查添加行的“位置”列是否等于我指定的位置就足够了。基于此,我会更改行的背景色。
代码是这样的:
private void setBindSource(BindingSource bindSource)
{
gridview.DataSource = bindSource;
gridview.EndEdit();
bindSource.EndEdit();
}
private void gridView_RowsAdded(object sender, System.Windows.Forms.DataGridViewRowsAddedEventArgs e)
{
if (e.RowIndex == -1 || e.RowCount == 0)
{
return;
}
for (int index = e.RowIndex; index <= e.RowIndex + e.RowCount - 1; index++)
{
DataGridView dgv = sender as DataGridView;
DataGridViewRow row = dgv.Rows[index];
if ((Int32)row.Cells["position"].Value == specificPosition)
row.DefaultCellStyle.BackColor = Color.Green;
}
}
我面临的问题:
rowsadded 事件按预期触发(在 gridview.DataSource = bindSource;)。但是该行本身没有任何数据(使用的数据表显示了预期的数据)。所以它显然会抛出错误,它找不到指定的列“位置”。我假设 gridview 还没有完全初始化?
添加行后如何更改行的颜色?
当行的背景颜色取决于特定的单元格值时,在“更改”行颜色时应牢记一些事项。
测试特定单元格值和更改行颜色的代码所在的“位置”可以在许多不同的网格事件中完成,并且所有事件(基本上)都会完成相同的事情。然而,做一些简单的测试来帮助您确定您选择的“网格事件”是否“真的”是您需要或应该使用的可能是有益的。
例如,按照建议,您可以订阅网格 CellFormatting
事件来执行您描述的操作,它将按预期工作。但是,使用此事件会产生一个微妙但可能存在的问题。对于初学者来说,几乎所有的网格“格式化”事件都会触发很多次。
如果用户只是将光标移到网格上,则将触发格式化事件。因此,如果光标正好移到目标单元格上,就会执行代码。这可能是可以接受的;但是,从这里可以清楚地看出,检查单元格的值确实是不必要的,因为单元格的值没有改变。用户只需将光标移动到目标单元格上。
如前所述,这可能是可以接受的,但是,如果这种不必要的事件调用混合在一起,不难看出这种情况的许多组合会影响 UI 的性能并且用户可能会遇到缓慢的 UI.
这里的主要思想是……不要将您的代码放在一个会被不必要地触发的事件中,这是一个很好的例子。它可能有效,但代码正在“创建”额外和不必要的执行步骤。
鉴于此,您尝试连接网格 RowsAdded
事件可能会奏效。但是,正如您所指出的,当数据“最初”加载时以及用户手动添加新行或代码添加新行时,似乎需要做一些不同的事情。当数据“初始”加载时,您认为某些单元格可能尚未初始化是正确的。至少你的代码正在查看的单元格。
这可以解决,但是,使用 RowsAdded
事件会遗漏另一个问题……
_“what if the user CHANGES a cells value of a ‘’position’’ cell?”
在这种情况下不会触发新行事件。如果用户将“位置”单元格更改为 specifiedPosition
的值,则该行的背景颜色将不会更改。
考虑到所有这些,为了提供帮助,最好将我们想要代码的“时间”指向 运行。据我所知,这将是“当”位置列中的单元格中的值发生变化时。因此,我建议您订阅 grids CellValueChanged
活动。如果“更改”的单元格是“位置”单元格,则测试单元格值并相应地为行着色。
这将最大限度地减少对代码的不必要调用次数,并将解决前面描述的用户“更改”单元格值时出现的问题。当“用户”添加新行时,这也将起作用。不幸的是,当最初加载数据或通过代码添加新行时,不会触发此事件。
鉴于此,除了在代码中为新添加的行设置正确的行颜色之外,还有一种可能的解决方案是在网格最初加载数据后为行着色,一些小方法可能会派上用场。
第一种方法只是根据“位置”单元格的值为给定的一 (1) 行着色。这假设给定的行不是 null
并且位置列存在并且它是有效的 int.
private void ColorRow(DataGridViewRow row) {
if ((int)row.Cells["position"].Value == specificPosition) {
row.DefaultCellStyle.BackColor = Color.LightGreen;
}
else {
row.DefaultCellStyle.BackColor = Color.White;
}
}
我们可以在网格 CellValueChanged
事件中使用 ColorRow
方法来为特定行着色。此外,在表单加载事件中,在数据初始设置到网格中之后,我们可以调用一个附加方法,该方法简单地循环遍历网格的所有行并调用上面的 ColorRow
方法。这个 ColorSpecificRows
方法可能看起来像……
private void ColorSpecificRows() {
foreach (DataGridViewRow row in gridView.Rows) {
if (!row.IsNewRow) {
ColorRow(row);
}
}
}
接下来,剩下的就是订阅网格 CellValueChanged
事件,它可能看起来像……
private void gridView_CellValueChanged(object sender, DataGridViewCellEventArgs e) {
ColorRow(gridView.Rows[e.RowIndex]);
}
为了帮助测试这个,下面是一个完整的例子。创建一个新的 win 表单解决方案,在表单中添加一个 DataGridView
和一个 Button
。该按钮用于演示以编程方式添加行。
DataTable GridTable;
BindingSource GridBS;
Random rand = new Random();
int specificPosition = 2;
int formattingCount = 0;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
GridTable = GetTable();
FillTable(GridTable);
GridBS = new BindingSource(GridTable, null);
gridView.DataSource = GridBS;
ColorSpecificRows();
}
private DataTable GetTable() {
DataTable dt = new DataTable();
dt.Columns.Add("Col0", typeof(string));
dt.Columns.Add("position", typeof(int));
dt.Columns.Add("Col2", typeof(string));
return dt;
}
private void FillTable(DataTable dt) {
for (int i = 0; i < 10; i++) {
dt.Rows.Add("C0R" + i, rand.Next(1, 4), "C2R" + i);
}
}
private void button1_Click(object sender, EventArgs e) {
GridTable.Rows.Add("new0", 2, "new0");
GridTable.Rows.Add("new1", 3, "new0");
GridTable.Rows.Add("new2", 2, "new0");
ColorSpecificRows();
}
最后,出于测试目的,您可以连接网格 CellFormatting
事件以演示调用该偶数的频率。
private void gridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) {
Debug.WriteLine("CellFormatting - Enter -- FormattingCount: " + ++formattingCount);
// code to change row color
Debug.WriteLine("CellFormatting - Leave");
}
我希望这是有道理的。