Matt Kent
Matt Kent

Reputation: 1185

DataGridView - Index was out of range.

Before anyone classes this as a duplicate, I have indeed searched both around StackOverflow and the Google for the solution to my problem, neither have proven to be successful.

To summarise: I am building a game as a part of a unit in my CS course "Object Oriented Programming". The aim of the game is to randomly generate planes, who's fuel level deducts using a timer and then events such as crash are fired upon the fuel reaching 0. We then have to land the planes and assign them runways, and so on...

This all works fine, however, I am at the stage where I have to list all the planes that are being generated and then give the user the option to land them.

I initially used a ListView but quickly switched to a DataGridView because I wanted to have a button as a column.

So, intially as the planes were being generated, and furthermore displayed within the DataGridView, whenever I clicked the "Land Plane" button within a row of my choosing the selection would simply jump back to the first row. I asked my lecturer for assitance, and he stated that it's because the fuel's value is constantly being updated as it counts down. When the DataGridView is cleared, the selected row resets.

To resolve this, we added two local variables to store the selected row and the selected column. We checked to see if the selected column still remained within the collection, when the "Land Plane" button was clicked. This is because when the fuel reaches 0 it simply removes the row from the DataGridView.

The problem I am now having, which my lecturer was puzzled by was this:

An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll

Additional information: Index was out of range. Must be non-negative and less than the size of the collection.

The code that handles the DataGridView is as follows:

Public Sub populateDataGV()
    Dim p As New Aircraft

    selRow = -1
    'Populate the data grid view
    If Not (IsNothing(DataGridView1.CurrentCell)) Then
        selRow = DataGridView1.CurrentCell.RowIndex
        selCol = DataGridView1.CurrentCell.ColumnIndex
    End If


    DataGridView1.Rows.Clear()
    DataGridView1.ColumnCount = 2
    DataGridView1.Columns(0).Name = "Flight No"
    DataGridView1.Columns(1).Name = "Fuel"

    For Each p In airport.planeCollection
        Dim row As String() = New String() {p.name, p.getFuelLevel()}
        DataGridView1.Rows.Add(row)
    Next

    Dim RowsToDelete As New List(Of DataGridViewRow)()
    For Each rows As DataGridViewRow In DataGridView1.Rows
        If rows.Cells(1).Value IsNot Nothing AndAlso rows.Cells(1).Value.ToString = "0" Then
            RowsToDelete.Add(rows)
            If selRow = rows.Index Then
                selRow = -1
            End If
        End If
    Next
    For Each rows As DataGridViewRow In RowsToDelete
        DataGridView1.Rows.Remove(rows)
    Next
    RowsToDelete.Clear()

    If selRow <> -1 And selRow <= DataGridView1.Rows.Count - 1 Then
        DataGridView1.CurrentCell = DataGridView1.Rows(selRow).Cells(selCol)
    End If


    'Add button column
    Dim btn As DataGridViewButtonColumn = New DataGridViewButtonColumn()
    btn.HeaderText = "Action"
    btn.Text = "Land Plane"
    btn.UseColumnTextForButtonValue = True
    DataGridView1.Columns.Add(btn)


End Sub

This is where the error is thrown:

If selRow <> -1 And selRow <= DataGridView1.Rows.Count - 1 Then
        DataGridView1.CurrentCell = DataGridView1.Rows(selRow).Cells(selCol)
    End If

If anyone can shed some light on what is actually causing this error I'd be most grateful.

Upvotes: 3

Views: 9661

Answers (1)

vbnet3d
vbnet3d

Reputation: 1151

Your range check is open to errors.

First, Your current code allows selRow to be less than -2:

If selRow <> -1 And selRow <= DataGridView1.Rows.Count - 1 Then
    DataGridView1.CurrentCell = DataGridView1.Rows(selRow).Cells(selCol)
End If

Second, you do not need to set the column... instead, just set it to 0 or 1.

You should change

If selRow <> -1 And selRow <= DataGridView1.Rows.Count - 1 Then
    DataGridView1.CurrentCell = DataGridView1.Rows(selRow).Cells(selCol)
End If

to

If selRow >= 0 And selRow <= DataGridView1.Rows.Count - 1 Then
         DataGridView1.CurrentCell = DataGridView1.Rows(selRow).Cells(1)
End If

This new code properly range checks both values.


Also, you need to remove from the top:

selRow = -1

Finally, to address the problem of selecting the right row, I suggest changing:

DataGridView1.Rows.Clear()
DataGridView1.ColumnCount = 2
DataGridView1.Columns(0).Name = "Flight No"
DataGridView1.Columns(1).Name = "Fuel"

For Each p In airport.planeCollection
    Dim row As String() = New String() {p.name, p.getFuelLevel()}
    DataGridView1.Rows.Add(row)
Next

to:

 ' DataGridView1.Rows.Clear()
    If DataGridView1.ColumnCount = 0 Then
        DataGridView1.ColumnCount = 2
        DataGridView1.Columns(0).Name = "Flight No"
        DataGridView1.Columns(1).Name = "Fuel"
    End If

    For Each p In airport.planeCollection
        Dim updated As Boolean = False
        For Each rows As DataGridViewRow In DataGridView1.Rows
            If rows.Cells(0).Value = p.name Then
                rows.Cells(1).Value = p.getFuelLevel
                updated = True
                Exit For
            End If
        Next
        If Not updated Then
            Dim row As String() = New String() {p.name, p.getFuelLevel()}
            DataGridView1.Rows.Add(row)
        End If
    Next

You should add/update rather than simply clearing and adding.

Upvotes: 3

Related Questions