DataGridView CellEnter事件首次加载RowCount显示异常问题
I've run into similar timing issues with DataGridView's event sequence when working with dynamic control creation and data binding, so let's break down what's happening and how to fix it.
What's Causing the Problem?
The root issue is event timing during initial data binding: when your user control first loads, the CellEnter event fires before the DataGridView finishes loading all rows from the DataSource. At this point, the control only has the default "new row" (since AllowUserToAddRow = True) plus a temporary empty row, hence the incorrect RowCount = 2. Later events like DataSourceChanged fire after the data is fully loaded, so they get the correct count.
Your workaround of destroying/re-creating the control exacerbates this because the initial CellEnter trigger happens even faster before the data binding completes fully.
Solutions to Fix the RowCount Display
1. Delay RowCount Fetch with BeginInvoke in CellEnter
The simplest fix is to use BeginInvoke to defer the label update until the UI thread has finished processing all pending data binding tasks. This ensures the DataGridView has fully loaded all rows before you check RowCount.
Modify your CellEnter event handler like this:
private void DataGridView_CellEnter(object sender, DataGridViewCellEventArgs e) { var dgv = sender as DataGridView; if (dgv == null || e.RowIndex < 0) return; // Defer the update to after UI thread finishes data loading BeginInvoke(new Action(() => { // Calculate actual data rows (exclude the "new row" if enabled) int actualRowCount = dgv.RowCount - (dgv.AllowUserToAddRow ? 1 : 0); int currentRowNumber = e.RowIndex + 1; // Handle the "new row" case if (e.RowIndex == dgv.NewRowIndex) { currentRowNumber = actualRowCount + 1; } // Update your label rowCountLabel.Text = $"{currentRowNumber} of {actualRowCount}"; })); }
2. Combine DataSourceChanged and CellEnter for Full Coverage
To handle both initial load and data updates (like row adds/deletes), add a DataSourceChanged handler to sync the label when the data source changes, and keep the modified CellEnter handler for row selection changes:
private void DataGridView_DataSourceChanged(object sender, EventArgs e) { var dgv = sender as DataGridView; if (dgv == null) return; UpdateRowCountLabel(dgv); } // Helper method to reuse label update logic private void UpdateRowCountLabel(DataGridView dgv) { int actualRowCount = dgv.RowCount - (dgv.AllowUserToAddRow ? 1 : 0); int currentRowNumber = 0; if (dgv.CurrentRow != null) { currentRowNumber = dgv.CurrentRow.Index + 1; if (dgv.CurrentRow.Index == dgv.NewRowIndex) { currentRowNumber = actualRowCount + 1; } } rowCountLabel.Text = $"{currentRowNumber} of {actualRowCount}"; }
Then call this helper method in your CellEnter handler (inside the BeginInvoke block) instead of duplicating code.
3. Manual Label Update After Control Re-Creation
Since you're destroying and re-adding the control to fix column residue, add a manual label update right after binding the data source. This ensures the label shows the correct count immediately without waiting for CellEnter:
In your form's button click handler:
private void TabSimulatorButton_Click(object sender, EventArgs e) { // Clean up old control if (_currentDataControl != null) { Controls.Remove(_currentDataControl); _currentDataControl.Dispose(); } // Create and configure new control var newDataControl = new YourDataGridViewUserControl(); newDataControl.DataGridView.DataSource = GetYourDataSource(); // Your data fetch logic // Manually update the label immediately after binding newDataControl.UpdateRowCountLabel(); // Add to form Controls.Add(newDataControl); _currentDataControl = newDataControl; }
Add the public UpdateRowCountLabel method to your user control:
public void UpdateRowCountLabel() { UpdateRowCountLabel(DataGridView); }
Why These Fixes Work
BeginInvokeensures we wait until the DataGridView has finished rendering all rows before checkingRowCount, avoiding the prematureCellEntertrigger issue.- Combining
DataSourceChangedandCellEntercovers both initial data load and user-driven row selection changes, plus handles row adds/deletes correctly. - Manual update after control re-creation skips the unreliable initial
CellEntertrigger and sets the label correctly right away.
This should resolve the inconsistent RowCount display in your CellEnter event, even for the problematic tables on first load.
内容的提问来源于stack exchange,提问作者CT19X

