Fix issue 15093: Removing multiple rows while selecting the last new-item row in DataGridView leads to exception - #15117
SimonZhao888 wants to merge 3 commits into
Conversation
…item row in DataGridView leads to exception
There was a problem hiding this comment.
🟡 Changes recommended
A moderate issue and a regression-test gap remain unresolved.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Fixes DataGridView synchronization failures when deleting rows involving the final new-item row.
Changes:
- Rebuilds bound rows for out-of-sync
ItemAddedevents. - Restores new-item row synchronization.
File summaries
| File | Summary | Findings |
|---|---|---|
src/System.Windows.Forms/System/Windows/Forms/Controls/DataGridView/DataGridView.DataConnection.cs |
Handles row resynchronization after affected ItemAdded events. |
Moderate (1 vote): Preserve or recompute the initiating row/current position across refresh. Nit (3 votes): Add a regression test for the reported sequence. |
Review details
Suppressed comments (1)
src/System.Windows.Forms/System/Windows/Forms/Controls/DataGridView/DataGridView.DataConnection.cs:607
- Rebuilding here changes
NewRowIndexwhileOnRowEnteris still processing the cell that initiatedAddNew.RefreshRowsclears and repopulates the rows, thenPushAllowUserToAddRowsappends the new-item row, so the originalrowIndex(the old asterisk row) now points at the phantom item. WhenOnRowEnterresumes atDataGridView.Methods.cs:17773,DataConnection.OnRowEntercan move the currency position back to that old index, leaving focus/editing on the phantom row instead of the newly added item. Preserve or recompute the initiating row/current position across this refresh.
_owner.RefreshRows(scrollIntoView: !_owner.InSortOperation);
- Files reviewed: 1/1 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #15117 +/- ##
=============================================
Coverage 37.24166% 37.24166%
=============================================
Files 246 246
Lines 9774 9774
Branches 1029 1029
=============================================
Hits 3640 3640
Misses 5970 5970
Partials 164 164
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
🟡 Changes recommended
Moderate issues remain in exception handling and regression-test coverage.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (1)
src/System.Windows.Forms/System/Windows/Forms/Controls/DataGridView/DataGridView.Methods.cs:20008
- The new test never enters the
*row, so it leavesIsInAddNewTransactionfalse and skips the new branch at lines 20006-20014. It would pass against the base implementation and does not reproduce the hidden pending item, the subsequent move away, or the second*-row activation that triggers #15093. Add the reported sequence and assert that the second activation does not throw and that the list and bound-row counts remain synchronized.
- Files reviewed: 3/3 changed files
- Comments generated: 2
- Review effort level: Lite
Fixes #15093
Root Cause
When deleting a selected row that includes the final "new item" row (the asterisk row), the bound data source may trigger an additional
ItemAddedevent. At this point, the number of items in the data source exceeds the number of bound rows inDataGridView.Rows, causing the row collection and theCurrencyManagerstate to fall out of sync. If the asterisk row is clicked again, the existing code treats this state as invalid and throws anInvalidOperationException.Proposed changes
ProcessDeleteKey, strengthen the handling of the "selection includes a new row" scenario: only invokeDeleteRow(NewRowIndex)to clean up the pending new-row transaction when a validAddNewtransaction exists and the index is valid.DataGridViewDataConnection.GetError(int rowIndex)andDataGridViewDataConnection.GetError(int boundColumnIndex, int columnIndex, int rowIndex):string.Emptyimmediately ifCurrencyManagerisnullorrowIndex >= CurrencyManager.Countto prevent out-of-bounds access.Customer Impact
Regression?
Risk
Screenshots
Before
Recording.2026-09-16.095825.mp4
After
Recording.2026-09-16.152747.mp4
Test methodology
Test environment(s)
Microsoft Reviewers: Open in CodeFlow