Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deleting From DGV -- Index [x] does not have a value

The Setup: I have a two DataGridViews, each bound to a BindingList<> of custom business objects. These grids have a special row containing the mathematical totals of all rows in that grid -- this special row is reflective of a corresponding special object in the BindingList<> (I specify that so that you are aware that this is not a row being added to the DGV, but an object being added to the BindingList<>).

The Error: There comes a time, periodically, where I must find and remove the Totals Row object from the BindingList<> (and thus from the DGV). Here is the original code I was using to do this:

private void RemoveTotalRow()
  {
     for (int i = UnderlyingGridList.Count - 1; i >= 0; i--)
     {
        if (UnderlyingGridList[i].IsTotalRow) UnderlyingGridList.RemoveAt(i);  
     }
  }

(It's not super-important, but the reason I'm cycling through all records is to protect against the possibility that there could be more than one Totals row, by mistake). This code works flawlessly for one of the two grids under all circumstances. However, on the second grid I get the following error when the RemoveAt method is called:

The following exception occurred in the DataGridView:  System.IndexOutOfRangeException: Index 5 does not have a value.    at System.Windows.Forms.CurrencyManager.get_Item(Int32 index)    at System.Windows.Forms.DataGridView.DataGridViewDataConnection.GetError(Int32 rowIndex)  To replace this default dialog please handle the DataError event.

...where '5' is the index of the totals row. I found this question, which is essentially the same, except that the accepted answer is to either: 1) Not use an underlying list, which I must do, or 2) Delete from the grid instead of from the list. I have tried #2 by replacing the innermost method call from my code example above with this:

if (UnderlyingGridList[i].IsTotalRow) brokenDataGrid.Rows.RemoveAt(i);

This throws the same error. I also found this question, which suggests rebinding after the change - however, this is not feasible as it is possible for this code to be called once per second and if the list is too heavily populated it will make the grid unusable (I know this from bad experiences).

I could just handle the grid's DataError event, but I'd rather not have the thing popping a million errors per minute, even if they are silent. Any help would be greatly appreciated.

like image 915
Chris Barlow Avatar asked Sep 06 '25 03:09

Chris Barlow


1 Answers

So this was a bizarre set of circumstances... but here goes:

1) The Grid in question has a SelectionChanged event defined, inside of which two lines of code are called:

Grid.ClearSelection(); 
Grid.Refresh(); 

These are here because I am faking out the grid into looking like there is a selected row, when in fact there is not one. By doing this I am able to customize the look of the grid.

2) The event that triggers the code from my question is the Sorted event of the grid.

Steps 3 and 4 are speculation on my part, but my testing seems to support the theory

3) The Grid.Sorted event apparently triggers this Grid.SelectionChanged event as well.

4) The Grid is now trying to Refresh the grid and also remove the totals row at the same time. Hence breakpointing makes it seem as though it should work, when in fact it will not.

Removing the Grid.Refresh() method call from the event above rectifies the problem completely. Upon inspecting the Grid.SelectionChanged event of the working grid, I found that only the ClearSelection() method is being called, not Refresh().

Thanks to those who helped here on the thread and in c# chat!

like image 110
Chris Barlow Avatar answered Sep 08 '25 00:09

Chris Barlow