Wickedman84
Wickedman84

Reputation: 21

ArgumentOutOfRangeException on Datagridview with 1 row

I have a strange problem. I have a form with on it 2 unbounded datagridviews and 2 buttons. With the buttons I switch the rows from 1 datagrid to the other. In the beginning the left datagrid is filled with a number of rows and the right datagrid is empty. So when I click on the button "Add" the selected row from the left datagrid is removed and added to the right datagrid. With the button "Delete" the selected row of the right datagrid is added back to the left datagrid.

When there is only one row in the right datagrid, and I select it to "delete" it, the row is removed from the right datagrid and added to the left without an exception. Now I have a situation where there is only one row in the left datagrid and when I click "Add" to move it to the right datagrid I get an ArgumentOutOfRangeException (index is out of bounds...)

Below is the code which throws the exception

     For i As Integer = DgvLeft.SelectedRows.Count - 1 To 0 Step -1

         ind = DgvLeft.SelectedRows(i).Index
         If ind > 0 Then
             DgvLeft.Rows.RemoveAt(ind)

         Else
             DgvLeft.Rows.Remove(DgvLeft.SelectedRows(i))
         End If
    Next

So I store the row index in a variable. The first time I used the RemoveAt function and the exception is thrown. To resolve this I added the If-structure and tried the Remove function. But again the exception is thrown.

I don't understand why the exception is thrown. I use the same code for the "delete" button and there it doesn't happen. Also when I store the RowIndex in a variable the index is known, but not when I try to Remove the row.

Can someone help me with this strange problem?

Upvotes: 0

Views: 668

Answers (3)

JohnG
JohnG

Reputation: 9469

Since the posted for loop is “broken”, I feel it is unnecessary to question what you are trying to accomplish here. However, given what you described where there are two grids and two buttons (Add/Delete) on a form. When the “Add” button is clicked, it moves the “selected rows” from the “left” grid to the “right” grid, and then deletes the “selected rows” rows from the “left” grid. If the “Delete” button is clicked, then the opposite process happens moving the “selected rows” from the right grid to the left grid, then delete the selected rows from the right grid.

If this is correct, then it appears you are making this more complicated than it has to be. This would be much easier if you used a data source of some form. However, to break the above problem down, it appears that two methods may come in handy for what you want to do. The first one could simply add the selected rows from one given grid to another given grid. The next method would simply delete the selected rows from a given grid. With these two methods implemented, the “add” button would be…

AddSelectedRows(dgvLeft, dgvRight)
RemoveSelectedRows(dgvLeft)

The delete button would be…

AddSelectedRows(dgvRight, dgvLeft)
RemoveSelectedRows(dgvRight)

Before I explain the code below, it should be noted that your current posted code is making a huge programming “no-no” and without question is a problem for you. As Mary and others have pointed out, “changing the value of the counter variable in a loop or (as the code does) changing the collection it is looping through is rarely if ever done.”

Try the code below it may make things easier,

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    AddColumns(dgvLeft)
    AddColumns(dgvRight)
    FillGrid(dgvLeft)
End Sub

Private Sub FillGrid(dgv As DataGridView)
    For i = 0 To 15
        dgv.Rows.Add("C0R" + i.ToString(), "C1R" + i.ToString(), "C2R" + i.ToString())
    Next
End Sub

Private Sub AddColumns(dgv As DataGridView)
    Dim txtCol = New DataGridViewTextBoxColumn()
    txtCol.Name = "Col0"
    txtCol.HeaderText = "Col 0"
    dgv.Columns.Add(txtCol)
    txtCol = New DataGridViewTextBoxColumn()
    txtCol.Name = "Col1"
    txtCol.HeaderText = "Col 1"
    dgv.Columns.Add(txtCol)
    txtCol = New DataGridViewTextBoxColumn()
    txtCol.Name = "Col2"
    txtCol.HeaderText = "Col 2"
    dgv.Columns.Add(txtCol)
End Sub

Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
    AddSelectedRows(dgvLeft, dgvRight)
    RemoveSelectedRows(dgvLeft)
End Sub


Private Sub btnDelete_Click(sender As Object, e As EventArgs) Handles btnDelete.Click
    AddSelectedRows(dgvRight, dgvLeft)
    RemoveSelectedRows(dgvRight)
End Sub

Private Sub RemoveSelectedRows(dgv As DataGridView)
    Dim totalRowsToDelete = dgv.SelectedRows.Count
    Dim selectedRow As DataGridViewRow
    For i = totalRowsToDelete - 1 To 0 Step -1
        selectedRow = dgv.SelectedRows(i)
        If (Not selectedRow.IsNewRow) Then
            dgv.Rows.RemoveAt(dgv.SelectedRows(i).Index)
        End If
    Next
End Sub

Private Sub AddSelectedRows(sourceDGV As DataGridView, destinationDGV As DataGridView)
    Dim selectedRowCount = sourceDGV.Rows.GetRowCount(DataGridViewElementStates.Selected)
    If (selectedRowCount > 0) Then
        Dim selectedRow As DataGridViewRow
        For i = 0 To selectedRowCount - 1
            selectedRow = sourceDGV.SelectedRows(i)
            If (Not selectedRow.IsNewRow) Then
                destinationDGV.Rows.Add(selectedRow.Cells(0).Value.ToString(),
                      selectedRow.Cells(1).Value.ToString(),
                      selectedRow.Cells(2).Value.ToString())
            End If
        Next
    End If
End Sub

Upvotes: 1

Wickedman84
Wickedman84

Reputation: 21

I want to thank Mary for her answer, because that made me think about my code. I looked at the code of the "delete" button, where I use the same for loop, and that code doesn't throw an exception. So there must be a difference between the code of my two buttons.

This is an expanded piece of my code in the "add" button:

    For i As Integer = DgvLeft.SelectedRows.Count - 1 To 0 Step -1
        'fill the array with the row values
         For j As Integer = 0 To DgvLeft.Columns.Count - 1
             fields(j) = DgvLeft.SelectedRows(i).Cells(DgvLeft.Columns(j).Name).Value
         Next

         'delete the row in datagrid Left
         ind = DgvLeft.SelectedRows(i).Index

         If ind > 0 Then
             DgvLeft.Rows.RemoveAt(ind)

         Else
             DgvLeft.Rows.Remove(DgvLeft.SelectedRows(i))
         End If

         'add the row in datagrid Right
         DgvRight.Rows.Add(fields)
    Next

In the code snippet above I attempt to remove a row BEFORE I add the array of values from this row to the other datagrid. When I looked at the code of the "delete" button I attempt to remove the row AFTER I add the array of values to the other datagrid.

So I moved this piece of code below the code of adding the array of values and it worked. Probably the index exception is thrown by the array rather than the datagridview.

Upvotes: 0

Mary
Mary

Reputation: 15091

You are changing the value of DgvLeft.SelectedRows.Count in your For loop. Try...

Dim RowCount As Integer = DgvLeft.SelectedRows.Count
For i As Integer = RowCount - 1 To 0 Step -1

Upvotes: 0

Related Questions