I have two datagridviews. One is dtgridPopulate and is populated with data from the database.
dtgridPopulate columns are (checkbox, code, name)
checkbox | code | name |
---|---|---|
checkbox icon | c1 | customer_one |
Then the second datagridview is dtgridGenerate which has generated values from dtgridPopulate.
I use the code dtgridPopulate.Rows.Add(code, name)
to add manually the value from dtgridPopulate to dtgridGenerate.
dtgridGenerate columns are (code, name)
code | name |
---|---|
c1 | customer_one |
When I check the checkbox in the dtgridPopulate it will transfer the values (code, name) to the dtgridGenerate. But the problem is when I uncheck the checkbox in the dtgridPopulate, It should also REMOVE the values in the dtgridGenerate.
Private Sub dtgridPopulateSelectAll_CurrentCellDirtyStateChanged(ByVal sender As Object, ByVal e As EventArgs) Handles dtgridPopulate.CurrentCellDirtyStateChanged
RemoveHandler dtgridPopulate.CurrentCellDirtyStateChanged, AddressOf dtgridPopulateSelectAll_CurrentCellDirtyStateChanged
If TypeOf dtgridPopulate.CurrentCell Is DataGridViewCheckBoxCell Then
dtgridPopulate.EndEdit()
Dim Checked As Boolean = CType(dtgridPopulate.CurrentCell.Value, Boolean)
If Checked Then
code = dtgridPopulate.CurrentRow.Cells(1).Value.ToString
name = dtgridPopulate.CurrentRow.Cells(2).Value.ToString
dtgridGenerate.Rows.Add(code, name)
Else
For Each drow As DataGridViewRow In dtgridPopulate.SelectedRows 'This is for uncheck but it doens't work
dtgridGenerate.Rows.Remove(row)
Next
End If
End If
AddHandler dtgridPopulate.CurrentCellDirtyStateChanged, AddressOf dtgridPopulateSelectAll_CurrentCellDirtyStateChanged
End Sub
I refer to this reference
Error when I uncheck the checkbox: row provided does not belong to this datagridview control. parameter name: datagridviewrow
CodePudding user response:
I am not sure “why” you have unsubscribed and then re-subscribed to the event. Typically, this is only needed if the code in the event “changes” something in the grid that would cause the event to re-fire and this is not happening in your current code. Nor is ending the grids edit necessary.
Also, your use of the grids CurrentCellDirtyStateChanged
event has one drawback in relation to what you want to do… it will NOT re-fire if the user checks and unchecks the same cell over and over. In other words, if the user clicks a check box cell and the check box becomes checked and the event fires… then … if the user “unchecks” the same cell before clicking on any other cell, then the event will NOT refire.
Also, it looks like the event is using a different grid from the signature of the event… dtgridPopulateSelectAll_CurrentCellDirtyStateChanged
… ? … “SelectAll” and the grid in the event is called… dtgridPopulate
… this is confusing.
Given this, I suggest two things to help. 1) create and use an “Empty” DataTable
for the second grid. This way we could simply add and remove items from that table. 2) use the grids CellContnetClick
event for this. It will re-fire if the user clicks on the same cell over and over in addition to firing ONLY when the check box is changed.
So, I propose these small changes. First add a global variable named generateDT
as a DataTable
used as a DataSource
to the second grid. Initially this table would be empty. Second use the grids CellContentClick
event to make these additions and removal of the rows.
Dim generateDT As DataTable
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim dt As DataTable = New DataTable()
dt.Columns.Add("checkbox", GetType(Boolean))
dt.Columns.Add("code", GetType(String))
dt.Columns.Add("Name", GetType(String))
dt.Rows.Add(False, "c1", "customer 1")
dt.Rows.Add(False, "c2", "customer 2")
dt.Rows.Add(False, "c3", "customer 3")
dtgridPopulate.DataSource = dt
generateDT = New DataTable()
generateDT.Columns.Add("code", GetType(String))
generateDT.Columns.Add("Name", GetType(String))
dtgridGenerate.DataSource = generateDT
End Sub
Then in the cell content click event, if the clicked cell is a check box cell, then… grab the checked state and both the code
and name
of the clicked-on row. Then if the check box cell is checked, then simply add the code
and name
to the second grids global DataTable
variable generateDT
. If the check box is unchecked, then we will loop through each row in the second grid and if we find a match then simply remove that row from the second grids global DataTable
… something like…
Private Sub dtgridPopulate_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles dtgridPopulate.CellContentClick
If e.ColumnIndex = 0 Then
Dim Checked = CType(dtgridPopulate.Rows(e.RowIndex).Cells(e.ColumnIndex).EditedFormattedValue, Boolean)
Dim code = dtgridPopulate.CurrentRow.Cells(1).Value.ToString
Dim Name = dtgridPopulate.CurrentRow.Cells(2).Value.ToString
If Checked Then
generateDT.Rows.Add(code, Name)
Else
Dim rowToRemove As DataRowView
For Each row As DataGridViewRow In dtgridGenerate.Rows
If row.Cells(0).Value.ToString() = code Then
rowToRemove = CType(row.DataBoundItem, DataRowView)
generateDT.Rows.Remove(rowToRemove.Row)
Exit For
End If
Next
End If
End If
End Sub