Reputation: 1185
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
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