0

I am working with forms in VB.NET

There is a DatagridView table with a checkbox column.

See the picture below:

datagridview with checkboxes column

I am interested in the question: how to add the line index to the list when clicking in the checkbox (when we activate the checked status), and remove it from the list when we uncheck the checkbox?

Tried the following but this is not the correct solution:

If e.ColumnIndex = chk_column.Index Then 
       
    If e.RowIndex >= 0 Then
        Try                 
            For Each row As DataGridViewRow In dataGridNames.Rows
                Dim cell As DataGridViewCheckBoxCell = TryCast(row.Cells(5), DataGridViewCheckBoxCell)
                If cell.Value Is cell.FalseValue Then
                    bList_indexes.Add(DataGridnames.CurrentCell.RowIndex)  
                    Exit For
    
                Else 'If  cell.Value Is cell.TrueValue Then
                    bList_indexes.RemoveAt(DataGridnames.CurrentCell.RowIndex) 
                End If
            Next
        Catch ex As Exception
            'Show the exception's message.
            'MessageBox.Show(ex.Message)
    
            'Throw New Exception("Something happened.")
        End try
    End If

End If
djv
  • 15,168
  • 7
  • 48
  • 72
elmund0
  • 3
  • 1
  • That code makes no sense. The whole point of that event is that it gives you row index and column index of the cell that was affected, so why would you loop through all rows in the grid? You've got the row index so you should only care about the row at that index. In fact, you don't even care about the row, given that your collection contains indexes. Just add the current index to the list or remove it from the list. That's it, that's all. – jmcilhinney Sep 23 '21 at 03:32

1 Answers1

0

Using DataSources allows you to take the logic out of mucking around in DataGridView events. You shouldn't perform [much] business logic on the UI anyways.

Here is the class I used to represent your data.

Public Class ClassWithSelect
    Public Property [Select] As Boolean
    Public Property Name As String
    Public Sub New(s As Boolean, n As String)
        Me.Select = s
        Me.Name = n
    End Sub
End Class

And all the code to set DataSources

Private myDataSource As List(Of ClassWithSelect)
Private selectedIndices As List(Of Integer)

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    myDataSource = Enumerable.Range(65, 10).Select(Function(i) New ClassWithSelect(False, Chr(i).ToString())).ToList()
    DataGridView1.DataSource = myDataSource
    updateSelectedIndices()
End Sub

Private Sub DataGridView1_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellValueChanged
    updateSelectedIndices()
End Sub
Private Sub DataGridView1_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick
    DataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit)
End Sub

Private Sub updateSelectedIndices()
    selectedIndices = New List(Of Integer)()
    For i = 0 To myDataSource.Count - 1
        If myDataSource(i).Select Then selectedIndices.Add(i)
    Next
    ListBox1.DataSource = selectedIndices
End Sub

And the end result

enter image description here

Now you don't need to access the UI to get the indices for further processing as they are in the class-level variable selectedIndices. The UI is meant for user I/O, NOT for storing state.

  • Note: The event handler was taken from this answer but this answer is also linked as an improvement to the check change handler, but I felt the complexity would distract from my answer. If you find you need to click fast, look into the latter.
  • Also Note: The method updateSelectedIndices() should have inside it an InvokeRequired check if you plan to perform work off the UI thread
djv
  • 15,168
  • 7
  • 48
  • 72