How to edit an access database? - vb.net

I made a flashcard application that stores the users flashcards into an access database where they will be able to revise from.
Here is part of the code from creating the flashcard
command = " insert into Flashcards ([Front],[Back],[Difficulty]) values ('" & txtFront.Text & "','" & txtBack.Text & "' ,'" & 3 & "')"
This stores flashcards in the below database
Access database
Here is part of the code for revising the flashcards
Private Sub btnEasy_Click(sender As Object, e As EventArgs) Handles btnEasy.Click
Dim index = rand.Next(dt.Rows.Count) ' generates index in the range 0 .. Count - 1
If txtBack.Visible = True Then 'If the back of the flashcard is shown
txtFront.Text = dt.Rows(index)(2).ToString() 'Displays a random record in the third column (front of flashcard)
txtBack.Visible = False 'Does not display the back of the flashcard
txtBack.Text = dt.Rows(index)(3).ToString() 'Displays a random record in the fourth column ()
Else 'If the user has not pressed the reveal button before
MsgBox("Please first reveal the back of the flashcard")
End If
End Sub
Private Sub btnGood_Click(sender As Object, e As EventArgs) Handles btnGood.Click
Dim index = rand.Next(dt.Rows.Count) ' generates index in the range 0 .. Count - 1
If txtBack.Visible = True Then
txtFront.Text = dt.Rows(index)(2).ToString()
txtBack.Visible = False
txtBack.Text = dt.Rows(index)(3).ToString()
Else
MsgBox("Please first reveal the back of the flashcard")
End If
End Sub
Private Sub btnHard_Click(sender As Object, e As EventArgs) Handles btnHard.Click
Dim index = rand.Next(dt.Rows.Count) ' generates index in the range 0 .. Count - 1
If txtBack.Visible = True Then
txtFront.Text = dt.Rows(index)(2).ToString()
txtBack.Visible = False
txtBack.Text = dt.Rows(index)(3).ToString()
Else
MsgBox("Please first reveal the back of the flashcard")
End If
End Sub
Right now btnEasy , btngood and btnhard all do the same thing but i want to know a way that pressing btnEasy for example will change the difficulty from 3 in the database to 1.
Also how would i get it so pressing btneasy will only randomy select flashcards that have a difficulty of 1 and not just randomy select a flashcard from the whole database.
Sorry, if the question is a bit long, ive been stuck on this for quite a while

you will want to filter the Datatable (dt in your code) to select only the records that are relevant to the "Difficulty" for the given button. From your image it seems that Easy = 1, Good = 2, and Hard = 3? If you are unfamiliar with selecting a subset of data from the DataTable, it should look something like this in your code:
' Use the Select method to find all rows matching the filter.
hardRows = dt.Select("Difficulty = 3")
Then you can randomly select from that subset or rows (rather than from dt.Rows.Count).
Also, for more information look this documentation from Microsoft: https://learn.microsoft.com/en-us/dotnet/api/system.data.datatable.select

Related

DataGridView live search data

I am trying to add a search function to a DataGridView in vb.net using this code
For i As Integer = 0 To ContactsList.RowCount - 1
For j As Integer = 0 To ContactsList.ColumnCount - 1
If ContactsList.Rows(i).Cells(j).Value.ToString.ToLower.Trim = ContactsListSearch.Text.ToLower.Trim Then
MsgBox("Item found " + i.ToString)
ContactsList.Rows(i).Visible = True
Else
ContactsList.Rows(i).Visible = False
End If
Next
Next
I'm seeing the MsgBox show when the value matches, but the rows are not showing, it just hides all rows
Another possible option is to load data into a DataTable, create a BindingSource, set the BindingSource DataSource property to the DataTable. Set the DataGridView DataSource property to the BindingSource.
The following example works against a column in the DataTable. If the user clears the TextBox the filter is removed while if there is text filter with trim.
Private Sub SearchButton_Click(sender As Object, e As EventArgs) _
Handles SearchButton.Click
If String.IsNullOrWhiteSpace(SearchTextBox.Text) Then
bindingSource.Filter = ""
Else
Dim currentRowCount = bindingSource.Count
bindingSource.Filter = $"TRIM(LastName) = '{SearchTextBox.Text}'"
MessageBox.Show($"Before: {currentRowCount} Now: {bindingSource.Count}")
End If
End Sub
Edit If the column name might be variable consider loading a ComboBox with column names then adjust code as follows.
bindingSource.Filter = $"TRIM({FilterComboBox.Text}) = '{SearchTextBox.Text}'"
In most cases working against a data source is better than working against cells values as per the above recommendation.
I added 2 Exits in the IF statement when the value matches as it's searching each column as well, so it was causing them to be hidden as it loops columns too
For i As Integer = 0 To ContactsList.RowCount - 1
For j As Integer = 0 To ContactsList.ColumnCount - 1
If ContactsList.Rows(i).Cells(j).Value.ToString.ToLower.Trim = ContactsListSearch.Text.ToLower.Trim Then
MsgBox("Item found " + i.ToString)
ContactsList.Rows(i).Visible = True
Else
ContactsList.Rows(i).Visible = False
End If
Next
Next

How to use function to prevent duplicated record for datagridview

I use function to prevent the same record goes into my datagridview but it doesnt work , when i separate the code out then its worked
i tried to seperate the for loop part out then the code work , but i wan to use function to do it so the code look more neater
Private Sub PicFavNote10_Click(sender As Object, e As EventArgs) Handles picFavNote10.Click
If validationDataGrid(lblNameNote10.Text) <> True Then
'if item didn added to the favorite data table yet
'add to favorite table
addTofavorite(lblUserLogin.Text, lblNameNote10.Text, lblDecpNote10.Text, txtPicNote10.Text, "SmartPhone", lblPriceNote10.Text)
End If
lblPriceNote10.Text = FormatCurrency(lblPriceNote10.Text)
End Sub
Private Function validationDataGrid(ByRef data As String) As Boolean
'validation on data grid view
For Each itm As DataGridViewRow In DGTFavTable.Rows 'loop though every item in datagrid
If itm.Cells(0).Value = data Then 'check wherter the text already exist
MsgBox(data & " Already added to your favorite cart")
Return True
Else
Return False
End If
Next
End Function
I expected the MsgBox(data & " Already added to your favorite cart") will excecute but instead the validationDataGrid function return false value even the item is already added to favorite datagridview
Before you loop all rows you need to call this sub as is an efficient workaround to validate new data on DataGridView:
Private Sub ForceGridValidation()
'Get the current cell
Dim currentCell As DataGridViewCell = DGTFavTable.CurrentCell
If currentCell IsNot Nothing Then
Dim colIndex As Integer = currentCell.ColumnIndex
If colIndex < DGTFavTable.Columns.Count - 1 Then
DGTFavTable.CurrentCell = DGTFavTable.Item(colIndex + 1, currentCell.RowIndex)
ElseIf colIndex > 1 Then
DGTFavTable.CurrentCell = DGTFavTable.Item(colIndex - 1, currentCell.RowIndex)
End If
'Set the original cell
DGTFavTable.CurrentCell = currentCell
End If
End Sub

Pass values from Numeric control into corresponding cells in DataGridView control with a button

I want to move the values from each of four Numeric Up/Down controls into the DataGridView columns/rows with a button. For instance, the operator sets the values in the up/down numeric controls and then clicks the button. The program should then add a new row to the DataGridView and pass whatever values that are in the Numeric Up/Down controls into the new cells of the new row. As of now, I have the adding new rows part of it working as well as the delete button working (delete last row of the DataGridView). Now, how to pass the Numeric control values into the cell of the new row of the DataGridView with the button? Each new row created of the DatGridView has four cells to correspond to the four Numeric up/down controls. Thank you.
Private Sub addStep_btn_Click(sender As Object, e As EventArgs) Handles addStep_btn.Click
LftMtr_Data_Grid.ColumnCount = 4
LftMtr_Data_Grid.RowCount = LftMtr_Data_Grid.RowCount + 1
LftMtr_Data_Grid.Columns(0).HeaderText = " Spindle Speed (rpm)"
LftMtr_Data_Grid.Columns(1).HeaderText = " Accel Rate (rpm/S)"
LftMtr_Data_Grid.Columns(2).HeaderText = " Decel Rate (rpm/S)"
LftMtr_Data_Grid.Columns(3).HeaderText = " Time (S)"
For Each c As DataGridViewColumn In LftMtr_Data_Grid.Columns
c.Width = 120
Next
Dim rowNumber As Integer = 1
For Each row As DataGridViewRow In LftMtr_Data_Grid.Rows
If row.IsNewRow Then Continue For
row.HeaderCell.Value = "Step " & rowNumber
rowNumber = rowNumber + 1
Next
LftMtr_Data_Grid.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders)
rowCount1 = LftMtr_Data_Grid.RowCount
txtBox1.Text = rowCount1
End Sub
Try something like below. Note that you don't need to setup the column headers everytime, just once in the Load() event would do!
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
LftMtr_Data_Grid.ColumnCount = 4
LftMtr_Data_Grid.Columns(0).HeaderText = " Spindle Speed (rpm)"
LftMtr_Data_Grid.Columns(1).HeaderText = " Accel Rate (rpm/S)"
LftMtr_Data_Grid.Columns(2).HeaderText = " Decel Rate (rpm/S)"
LftMtr_Data_Grid.Columns(3).HeaderText = " Time (S)"
For Each c As DataGridViewColumn In LftMtr_Data_Grid.Columns
c.Width = 120
Next
LftMtr_Data_Grid.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders)
End Sub
Private Sub addStep_btn_Click(sender As Object, e As EventArgs) Handles addStep_btn.Click
Dim values() As Object = {NumericUpDown1.Value, NumericUpDown2.Value, NumericUpDown3.Value, NumericUpDown4.Value}
Dim index As Integer = LftMtr_Data_Grid.Rows.Add(values)
LftMtr_Data_Grid.Rows(index).HeaderCell.Value = "Step " & (index + 1)
LftMtr_Data_Grid.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders)
End Sub
Private Sub delStep_btn_Click(sender As Object, e As EventArgs) Handles delStep_btn.Click
If LftMtr_Data_Grid.Rows.Count > 0 Then
LftMtr_Data_Grid.Rows.RemoveAt(LftMtr_Data_Grid.Rows.Count - 1)
End If
End Sub
End Class
I figured it out on my own. Here is what I came up with:
Dim rowNumber As Integer = 1
For Each row As DataGridViewRow In LftMtr_Data_Grid.Rows
If row.IsNewRow Then Continue For
row.HeaderCell.Value = "Step " & rowNumber
LftMtr_Data_Grid.CurrentCell = LftMtr_Data_Grid.Rows(LftMtr_Data_Grid.RowCount - 1).Cells(0)
LftMtr_Data_Grid.CurrentRow.Cells(0).Value = LftMtr_Speed_Incr.Value
LftMtr_Data_Grid.CurrentRow.Cells(1).Value = LftMtr_Accel_Incr.Value
LftMtr_Data_Grid.CurrentRow.Cells(2).Value = LftMtr_Decel_Incr.Value
LftMtr_Data_Grid.CurrentRow.Cells(3).Value = test_Time_Incr1.Value
rowNumber = rowNumber + 1
Next
This application works with an empty or partially filled dataGridView. When the user clicks the button, the code creates a new row in the dataGridView, makes the new row the selected row, and then finally populates each of the cells in the new row with the values that are in the four Numeric Up/down controls (could be a text box too depending on your application). This is code copied directly from my specific application. Yours may differ slightly with variable names, label text, etc.

What is wrong with my subroutines?

So I've been working on this project for a couple of weeks, as I self teach. I've hit a wall, and the community here has been so helpful I come again with a problem.
Basically, I have an input box where a user inputs a name. The name is then displayed in a listbox. The name is also put into an XML table if it is not there already.
There is a button near the list box that allows the user to remove names from the list box. This amends the XML, not removing the name from the table, but adding an end time to that name's child EndTime.
If the user then adds the same name to the input box, the XML gets appended to add another StartTime rather than create a new element.
All of this functions well enough (My code is probably clunky, but it's been working so far.) The problem comes when I try to validate the text box before passing everything through to XML. What I am trying to accomplish is that if the name exists in the listbox on the form (i.e hasn't been deleted by the user) then nothing happens to the XML, the input box is cleared. This is to prevent false timestamps due to a user accidentally typing the same name twice.
Anyhow, I hope that makes sense, I'm tired as hell. The code I've got is as follows:
Private Sub Button1_Click_2(sender As System.Object, e As System.EventArgs) Handles addPlayerButton.Click
playerTypeCheck()
addPlayerXML()
clearAddBox()
End Sub
Private Sub playerTypeCheck()
If playerTypeCBox.SelectedIndex = 0 Then
addMiner()
ElseIf playerTypeCBox.SelectedIndex = 1 Then
addHauler()
ElseIf playerTypeCBox.SelectedIndex = 2 Then
addForeman()
End If
End Sub
Private Sub addMiner()
If minerAddBox.Text = String.Empty Then
Return
End If
If minerListBox.Items.Contains(UCase(minerAddBox.Text)) = True Then
Return
Else : minerListBox.Items.Add(UCase(minerAddBox.Text))
End If
If ComboBox1.Items.Contains(UCase(minerAddBox.Text)) = True Then
Return
Else : ComboBox1.Items.Add(UCase(minerAddBox.Text))
End If
End Sub
Private Sub addPlayerXML()
If System.IO.File.Exists("Miners.xml") Then
Dim xmlSearch As New XmlDocument()
xmlSearch.Load("Miners.xml")
Dim nod As XmlNode = xmlSearch.DocumentElement()
If minerAddBox.Text = "" Then
Return
Else
If playerTypeCBox.SelectedIndex = 0 Then
nod = xmlSearch.SelectSingleNode("/Mining_Op/Miners/Miner[#Name='" + UCase(minerAddBox.Text) + "']")
ElseIf playerTypeCBox.SelectedIndex = 1 Then
nod = xmlSearch.SelectSingleNode("/Mining_Op/Haulers/Hauler[#Name='" + UCase(minerAddBox.Text) + "']")
ElseIf playerTypeCBox.SelectedIndex = 2 Then
nod = xmlSearch.SelectSingleNode("/Mining_Op/Foremen/Foreman[#Name='" + UCase(minerAddBox.Text) + "']")
End If
If nod IsNot Nothing Then
nodeValidatedXML()
Else
Dim docFrag As XmlDocumentFragment = xmlSearch.CreateDocumentFragment()
Dim cr As String = Environment.NewLine
Dim newPlayer As String = ""
Dim nod2 As XmlNode = xmlSearch.SelectSingleNode("/Mining_Op/Miners")
If playerTypeCBox.SelectedIndex = 0 Then
newMinerXML()
ElseIf playerTypeCBox.SelectedIndex = 1 Then
newHaulerXML()
ElseIf playerTypeCBox.SelectedIndex = 2 Then
newForemanXML()
End If
End If
End If
Else
newXML()
End If
End Sub
Private Sub nodeValidatedXML()
If playerTypeCBox.SelectedIndex = 0 Then
minerValidatedXML()
ElseIf playerTypeCBox.SelectedIndex = 1 Then
haulerValidatedXML()
ElseIf playerTypeCBox.SelectedIndex = 2 Then
foremanValidatedXML()
End If
End Sub
Private Sub minerValidatedXML()
If minerListBox.Items.Contains(UCase(minerAddBox.Text)) = False Then
appendMinerTimeXML()
End If
End Sub
Private Sub appendMinerTimeXML()
Dim xmlSearch As New XmlDocument()
xmlSearch.Load("Miners.xml")
Dim docFrag As XmlDocumentFragment = xmlSearch.CreateDocumentFragment()
Dim cr As String = Environment.NewLine
Dim newStartTime As String = Now & ", "
Dim nod2 As XmlNode = xmlSearch.SelectSingleNode("/Mining_Op/Miners/Miner[#Name='" & UCase(minerAddBox.Text) & "']/StartTime")
docFrag.InnerXml = newStartTime
nod2.AppendChild(docFrag)
xmlSearch.Save("Miners.xml")
End Sub
And lastly, the clearAddBox() subroutine
Private Sub clearAddBox()
minerAddBox.Text = ""
End Sub
So, I should point out, that if I rewrite the nodeValidated() Subroutine to something like:
Private Sub nodeValidatedXML()
If playerTypeCBox.SelectedIndex = 0 Then
appendMinerTimeXML()
ElseIf playerTypeCBox.SelectedIndex = 1 Then
appendHaulerTimeXML()
ElseIf playerTypeCBox.SelectedIndex = 2 Then
appendForemanTimeXML()
End If
End Sub
then all of the XML works, except it adds timestamps on names that already exist in the list, which is what i'm trying to avoid. So if I haven't completely pissed you off yet, what is it about the minerValidated() subroutine that is failing to call appendMinerTimeXML()? I feel the problem is either in the minerValidated() sub, or perhaps clearAddBox() is somehow firing and I'm missing it? Thanks for taking the time to slog through this.
Edit: Clarification. The code as I have it right now is failing to append the XML at all. Everything writes fine the first time, but when I remove a name from the list and then re-add, no timestamp is added to the XML.
You need to prevent the user accidentally typing the name twice.(Not sure if you mean adding it twice)
For this I believe you need to clear the minerAddBox.Text in your addminer() if this line is true.
minerListBox.Items.Contains(UCase(minerAddBox.Text)) = True
minerAddBox.Text = ""
Return
Now it will return back to your addplayerXML which will Return to your clearbox(), since you have this in your addplayerXML()
If minerAddBox.Text = "" Then
Return
Now you get to your clearbox() (Which is not really needed now since you cleared the minerAddBox.Text already)
when I remove a name from the list and then re-add, no timestamp is added to the XML.
your minerValidatedXML() is true, because you are not clearing the textbox when you re-add a name to the list box. Or you may need to remove the existing listbox item if it is the same as the textbox
If minerListBox.Items.Contains(UCase(minerAddBox.Text)) = True Then
minerListBox.Items.remove(UCase(minerAddBox.Text))

Dual check box selection vb / winform

I am after a little bit of help:
I have a datagridview control where I add another couple of columns (as check boxes) in order to select multiple rows. When I select the first checkbox column I want the second to be selected automatically, but can then be de-selected if required. And if the first checkbox is deselected, the 2nd is auto deselected too.
I have this working with the following code:
Private Sub dgvBikeAvailability_CellContentClick(sender As System.Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvBikeAvailability.CellContentClick
Debug.Print("Row index = " + e.RowIndex.ToString + ". Column index = " + e.ColumnIndex.ToString + ". Column Name = ")
'Debug.Print()
'when a bike is selected, a helmet is automatically selected, but can be deselected if the customer requires
If e.ColumnIndex = 0 Then
dgvBikeAvailability.Rows(e.RowIndex).Cells(0).Value = Not dgvBikeAvailability.Rows(e.RowIndex).Cells(0).Value
dgvBikeAvailability.Rows(e.RowIndex).Cells(1).Value = dgvBikeAvailability.Rows(e.RowIndex).Cells(0).Value
End If
End Sub
Unfortunately, wen the datagridview is refreshed, the column indexes are incremented, and the column indexes for the 2 check box columns are now 2 and 3.
I would like to be able to refer to them by name. They are declared in the sub that refreshes the datagridview:
colBikeSelectionCheckBox.HeaderText = "Select Bike"
colBikeSelectionCheckBox.Name = "colSelectBike")
colHelmetCheckBox.Name = "colSelectHelmet"
dgvBikeAvailability.Columns.Add(colHelmetCheckBox)
but the System.Windows.Forms.DataGridViewCellEventArgs class does not allow me to select column name.
Any ideas and suggestions will be greatly appreciated!
Edit: More in depth code segment:
Private Sub frmBikeHire_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
refreshGrid()
getStaffMember()
End Sub
'loads and refreshes the dgv
Private Sub refreshGrid()
Dim i As Integer
'initially fill in the rental dates for current day
txtDateFrom.Text = CStr(MonthCalendar1.SelectionRange.Start)
txtDateTo.Text = CStr(MonthCalendar1.SelectionRange.End)
'grab data from DB, set as dgv datasource
startDate = CStr(MonthCalendar1.SelectionRange.Start)
endDate = CStr(MonthCalendar1.SelectionRange.End)
dtBikeAvailability = sqlFuncDB_getDataTable("SELECT * FROM tb_bikeDetail WHERE bikeid NOT IN (SELECT DISTINCT bikeid FROM tb_bikemovements WHERE bikeMovementDate BETWEEN '" + func_convertDateSQLSERVER(startDate) + "' AND '" + func_convertDateSQLSERVER(endDate) + "') AND bikeid NOT IN (SELECT tb_bikemovements.bikeid FROM tb_bikemovements JOIN (SELECT bikeid, max(bikemovementdate) bmd FROM tb_bikemovements WHERE bikemovementdate < '" + func_convertDateSQLSERVER(startDate) + "' group by bikeid) lastmove ON lastmove.bikeid=tb_bikemovements.bikeid AND lastmove.bmd=tb_bikemovements.bikemovementdate WHERE bikeMovementType = '0')")
dvBikeAvailability = New DataView(dtBikeAvailability)
dgvBikeAvailability.DataSource = dvBikeAvailability
'switch off all columns
For i = 0 To dgvBikeAvailability.Columns.Count - 1
dgvBikeAvailability.Columns(i).Visible = False
Next
'displays only relevant column(s)
dgvBikeAvailability.Columns("bikeName").Visible = True
dgvBikeAvailability.Columns("bikeName").HeaderText = "Bike Name"
dgvBikeAvailability.Columns("bikeStyle").Visible = True
dgvBikeAvailability.Columns("bikeStyle").HeaderText = "Bike Style"
dgvBikeAvailability.Columns("bikeColour").Visible = True
dgvBikeAvailability.Columns("bikeColour").HeaderText = "Bike Colour"
'remove this line for program deployment
dgvBikeAvailability.Columns("bikeID").Visible = True
dgvBikeAvailability.Columns("bikeID").HeaderText = "Bike Number"
'add new check box column for selecting the bike
Dim colBikeSelectionCheckBox As New DataGridViewCheckBoxColumn
colBikeSelectionCheckBox.DataPropertyName = "PropertyName"
colBikeSelectionCheckBox.HeaderText = "Select Bike"
colBikeSelectionCheckBox.Name = "colSelectBike"
dgvBikeAvailability.Columns.Add(colBikeSelectionCheckBox)
'add new column for selecting helmet - consider adding as default setting
Dim colHelmetCheckBox As New DataGridViewCheckBoxColumn
colHelmetCheckBox.DataPropertyName = "PropertyName"
colHelmetCheckBox.HeaderText = "Helmet?"
colHelmetCheckBox.Name = "colSelectHelmet"
dgvBikeAvailability.Columns.Add(colHelmetCheckBox)
dgvBikeAvailability.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill
End Sub
Private Sub MonthCalendar1_DateChanged(sender As System.Object, e As System.Windows.Forms.DateRangeEventArgs) Handles MonthCalendar1.DateChanged
refreshGrid()
End Sub
Private Sub dgvBikeAvailability_CellClick(sender As Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvBikeAvailability.CellClick
Debug.Print("Row index = " + e.RowIndex.ToString + ". Column index = " + e.ColumnIndex.ToString + ". Column Name = " + dgvBikeAvailability.Rows(e.RowIndex).Cells("colSelectBike").OwningColumn.ToString)
If dgvBikeAvailability.Columns(e.ColumnIndex).Name = "colSelectBike" Then
dgvBikeAvailability.Rows(e.RowIndex).Cells("colSelectBike").Value = Not dgvBikeAvailability.Rows(e.RowIndex).Cells("colSelectBike").Value
dgvBikeAvailability.Rows(e.RowIndex).Cells("colSelectHelmet").Value = dgvBikeAvailability.Rows(e.RowIndex).Cells("colSelectBike").Value
End If
End Sub
I am unsure why that doesn't work. Each time the calendar control is changed it refreshes the datagridview, which is increasing the column index.
You can use the column index provided by the DataGridViewCellEventArgs class to retrieve the column and from that get the name to compare.
So something like:
If dgvBikeAvailability.Columns(e.ColumnIndex).Name == "colSelectBike" Then
' Your logic here
End If
For referencing the columns within your code to toggle the CheckBoxes, you can very happily use the names, and in fact do not need the index provided by the event args. The event args index appears to only be used to check that one of your desired columns was selected.
dgvBikeAvailability.Rows(e.RowIndex).Cells("colSelectBike").Value = Not dgvBikeAvailability.Rows(e.RowIndex).Cells("colSelectBike").Value
dgvBikeAvailability.Rows(e.RowIndex).Cells("colSelectHelmet").Value = dgvBikeAvailability.Rows(e.RowIndex).Cells("colSelectBike").Value
Although the code above should work it appears that something odd is happening with your grid. A quick solution is to instead of using the .Add() to use the .Insert() method of the DataGridView, which provided an index parameter, allowing you to directly control where your column goes.