Question Problem deleting row from datagridview

joefa

Member
Joined
Sep 16, 2010
Messages
19
Programming Experience
5-10
Hi

I wonder if anyone could help with this issue. I have an unbound datagridview from which I am trying to remove the top half of all the rows. Currently I am doing this:

<CODE>
Dim totalRows As Short = dataGridView.Rows.Count
For Each indexRow As DataGridViewRow In dataGridView.Rows
indexRow.Cells(9).Value = indexRow.Index
Next
For Each deleteRow As DataGridViewRow In dataGridView.Rows
'If deleteRow.Cells(9).Value < totalRows / 2 Then dataGridView.Rows.Remove(deleteRow)
If deleteRow.Cells(9).Value < totalRows / 2 Then deleteRow.Cells(1).Value = "DELETE"
Next
dataGridView.Sort(dataGridView.Columns(0), System.ComponentModel.ListSortDirection.Ascending)
</CODE>

This works in as much as it correctly identifies the rows meant for deletion, and marks them on the screen with "DELETE". However, if I comment out this line and instead uncomment the line above it which is actually meant to perform the deletion, I get an unhandled exception.

ArgumentOutOfRangeException was unhandled
Row index provided is out of range
Parameter name: rowindex
No Source Available
No symbols are loaded for any call stack frame. The source code cannot be displayed.

The code above is contained within a try-catch block, so to get an unhandled exception I think it must have occured deeper down in the class framework than I can see the code for.

I've been struggling with this for a while, so I would appreciate it if anyone has any ideas.

Thanks
 
Most likely because you are deleting items in the list you are enumerating. When you delete an item, the list is changed which can result in the ArgumentOutofRangeException. The best way to deal with enumerating a list when you plan to delete items of that list is to use an integer variable as a counter and step backwards through the list.

VB.NET:
For i as integer = CInt(totalRows / 2) - 1 to 0 step -1
    'Dim deleteRow as DataGridViewRow = dataGridView.Rows(i)
...
 
Hi, thanks for the reply. Unfortunately this approach still gives the same error. Probably I should have given some more detail than I did, so here you go:

The datagridview shows a list of appointments in chronological order, which are stored in a database table. The idea is that the the user drags the boundary of the appointment slot (event is DataGridView.RowHeightChanged), and this changes the length of the appointment in the database (and pushes the next appointment on etc), and updates the display accordingly with the new length, and the new time for the next appointment.

This works fine in that the database updates correctly, and indeed if you perform the dragging event, allowing the database to udpate, and then close the form and open it again, everything displays perfectly. The problem I'm having is that I can't get the display to refresh correctly on the fly. My first approach was to simply use DataGridView.Rows.Clear, then repopulate the datatable from the database, and from that redraw the grid with the new data. (This works fine for any other operation the user performs, e.g. changing the patient of an appointment). However, using the Sub I already have to do this after the RowHeightChanged event gave the mysterious unhandled ArgumentOutOfRange exception. After fiddling with this for ages, I eventually gave up and tried to work around it by first adding the new set of rows into the grid, then deleting the old ones above them (what I was talking about in the initial post). I thought this might work because this way the grid is never reduced to zero rows. But no, same error, and I'm pulling my hair out.

Sorry if that was a bit long but I thought it might help to explain the context. I'll keep trying, but if there are any other suggestions it'd be much appreciated.
 
Okay I've found a hacky workaround for this, so I can live with it for the time being, but I'd still like to resolve it.
 
Yeah don't worry, I think I'd have to post the entire class for that, so you could see different circumstances in which the method is called. I'll shelve it and come back to it later, make do with the workaround for now. Thanks anyway.
 
I use a variation on Paszt's code, which works fine :-

VB.NET:
For i as integer = CInt(totalRows / 2) - 1 to 0 step -1
    dataGridView.Rows.RemoveAt(i)
Next
 
Same error unfortunately. I'm sure just about every method I've tried would work under 'normal' circumstances. There's just something bizarre about what I've done and I can't figure out what it is. Thanks anyway.
 
Sorry to resurrect this old thread, but I've returned to have another look at this, and I've defined the problem much more clearly. What is boils down to is this: the exception is thrown if I remove rows from the DataGridView on its own RowHeightChanged event. In other words, it looks like you can't do this:

VB.NET:
    Private Sub dgv1_RowHeightChanged(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewRowEventArgs) Handles dgv1.RowHeightChanged
        dgv1.Rows.Clear()
    End Sub

So the question is now, does anyone know how/if this can be done?

Thanks again
Joe
 
Have you tried this :-

VB.NET:
Private Sub dgv1_RowHeightChanged(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewRowEventArgs) Handles dgv1.RowHeightChanged
        dgv1.DataSource = nothing
    End Sub
 
Thanks for the reply, but unfortunately the datagridview is unbound :rolleyes:

I'm going to try to investigate whether there is any event which occurs immediately after the RowHeightChanged event, or if not, if there is any way of creating one.

If you know anything about this I'm all ears!

Cheers for the help
Joe
 
Got it!

Okay, I've finally solved this. Hopefully the fix might help someone else. What I did is below. tmrRefresh is a Timer with an Interval of 1 millisecond.

VB.NET:
    Private Sub dgv1_RowHeightChanged(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewRowEventArgs) Handles dgv1.RowHeightChanged
        tmrRefresh.Start()
    End Sub

    Private Sub tmrRefresh_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrRefresh.Tick
        tmrRefresh.Stop()
        ExecuteCodeWhichDeletesRows()
    End Sub

So I used to timer to artificially create a new event, which occurs immediately after the RowHeightChanged event, and deleted the rows during the new event.

You might say this is a hack, but I'd prefer to call it a creative solution :) Hope it helps somebody.
 
Back
Top