Reputation: 167
I've got a project with a DataGridView showing data from a flat file database. There are 7 buttons that load an SQL querys result to the DGV, as well as adding a checkbox to select rows.
When a user selects a checkbox, that particular DataGridViewRow (DGVR) gets added to a temporary List(Of DGVR) for later use.
Then there's a final button that shows a second form, doing a comparison of the two entries selected, passing the temporary list to the second form.
Users will be able to select 1 from 2 different selections (hence the separate lists).
The problem is, if you click button 1, and choose a row, when you click a second button, the line that resets the datasource to the new query results apparently turns all existing DGVRs into null pointers.
IE: the references to the DGVR are lost.
If you pick one from the first button, and then one from the second button, then try and pass the two selected items, the first one will be null, but the second won't.
Code:
Dim con As New OleDb.OleDbConnection
Dim dbProvider As String
Dim dbSource As String
currentWeapon = "Sniper"
Dim ds As New DataSet
Dim da As New OleDb.OleDbDataAdapter
Dim sql As String
dbProvider = "PROVIDER=Microsoft.ACE.OLEDB.12.0;"
dbSource = "Data Source = Resources/Battlefield 4 Weapons.accdb"
con.ConnectionString = dbProvider & dbSource
con.Open()
sql = "SELECT * FROM [Battlefield 4 Weapons]"
da = New OleDb.OleDbDataAdapter(sql, con)
da.Fill(ds, "Battlefield 4 Weapons.accdb")
con.Close()
Dim dt As DataTable = ds.Tables(0)
Dim dr As DataRow() = dt.Select("[Weapon type] = 'Sniper'", "Weapon Name")
Dim miniDT As New DataTable
miniDT = dr.CopyToDataTable()
DataGridView1.DataSource = miniDT
DataGridView1.Sort(DataGridView1.Columns("Weapon Name"), System.ComponentModel.ListSortDirection.Ascending)
DataGridView1.MultiSelect = True
The line that nullifies the entries when a new button is pressed is the line:
DataGridView1.DataSource = miniDT
Then, when the checkbox gets clicked, this code runs (with a case for each weapon type). AsList is the list designed to hold the rows temporarily before passing them over:
DataGridView1.EndEdit()
Select Case currentWeapon
Case "Assault"
Assaultlabel.Visible = True
AsList.RemoveRange(0, AsList.Count)
For i = 0 To DataGridView1.Rows.Count - 1
If DataGridView1.Rows(i).Cells(14).Value = True Then
If Not AsList.Contains(DataGridView1.Rows(i)) Then
AsList.Add(DataGridView1.Rows(i))
End If
End If
Next
I've tried cloning the row, to create a copy that is separate, but that doesn't work. How can I separate it from the data source so that I can load a new set of data, but SAVE the selected rows?
Upvotes: 0
Views: 208
Reputation: 9981
The DataGridView will remove all rows whenever the DataSource is changed. You always need to reference the underlying data. I think it's time to understand how a DataTable is bound to the grid.
When you set a new data source the grid will see if the type of the new object implements the IListSource interface. A DataTable implements this interface. It returns the DefaultView and it's actually this instance that the grid use as its source. The grid create new rows and each row are bound to a DataRowView (which in turn is bound to a DataRow).
DataGridView > DataView > DataTable
DataGridViewRow > DataRowView > DataRow
You can obtain a reference to a DataRowView through the DataBoundItem property of the DataGridViewRow:
Dim gridRow As DataGridViewRow = Me.DataGridView1.Rows(0)
Dim viewRow As DataRowView = DirectCast(gridRow.DataBoundItem, DataRowView)
Dim tableRow As DataRow = viewRow.Row
Instead of copying a data table, just create a new data view:
Dim view1 As New DataView(mytable)
Dim view2 As New DataView(mytable)
You can sort and filter a data view.
view1.Sort = "Name ASC"
view1.RowFilter = "Name = 'Smith' And Age >= 18"
Now you can use this DataView as the data source instead the default view.
Me.DataGridView1.DataSource = view1
Upvotes: 1