vb.netfor-loopcheckedlistbox

How to get item text from CheckedListBox to ListBox without repeating the before text? VB.net


I have a CheckedListBox of 10 names A to J (it's a string but here I'm just using abc), and I want to make it so that every time a user check something, the text will be shown in the listbox simultaneously. I have tried this:

For i = 0 To chklistbxDrugAvailableList.Items.Count - 1
            Dim drugs As String = CType(chklistbxDrugAvailableList.Items(i), String)
            If chklistbxDrugAvailableList.GetItemChecked(i) Then
                listbxYourOrder.Items.Add(drugs)
            End If
           'drugs = nothing
Next

But when I check A,B,C the text in the Listbox got repeated like so:

A
A
B
A
B
C

I don't know why this is happening. I didn't declare drugs as an array. Even when I used the drugs = nothing, it still give repeated values.

What should I do? Sorry if this is a noob question.


Solution

  • Here is how I would do the whole thing:

    Private Sub CheckedListBox1_ItemCheck(sender As Object, e As ItemCheckEventArgs) Handles CheckedListBox1.ItemCheck
        'Clear the current ListBox contents.
        ListBox1.Items.Clear()
    
        'Get the indexes of the currently checked items.
        Dim checkedIndices = CheckedListBox1.CheckedIndices.Cast(Of Integer)()
    
        'Add the current index to the list if the item is being checked, otherwise remove it.
        checkedIndices = If(e.NewValue = CheckState.Checked,
                            checkedIndices.Append(e.Index),
                            checkedIndices.Except({e.Index}))
    
        'Get the checked items in order and add them to the ListBox.
        ListBox1.Items.AddRange(checkedIndices.OrderBy(Function(n) n).
                                               Select(Function(i) CheckedListBox1.Items(i)).
                                               ToArray())
    End Sub
    

    or like this:

    Private Sub CheckedListBox1_ItemCheck(sender As Object, e As ItemCheckEventArgs) Handles CheckedListBox1.ItemCheck
        'Get the indexes of the currently checked items.
        Dim checkedIndices = CheckedListBox1.CheckedIndices.Cast(Of Integer)()
    
    
        'Add the current index to the list if the item is being checked, otherwise remove it.
        checkedIndices = If(e.NewValue = CheckState.Checked,
                            checkedIndices.Append(e.Index),
                            checkedIndices.Except({e.Index}))
    
        'Get the checked items in order and add them to the ListBox.
        ListBox1.DataSource = checkedIndices.OrderBy(Function(n) n).
                                             Select(Function(i) CheckedListBox1.Items(i)).
                                             ToArray()
    End Sub
    

    The difference is that, because the second option uses data-binding, the first item in the ListBox will be selected by default.

    The reason that it needs to be a bit verbose is that the ItemCheck event is raised before the item is checked or unchecked. For that reason, we need to get the currently checked items first and then either add or remove the current item, depending on whether the current item is being checked or unchecked.

    EDIT:

    Here's an option that doesn't require clearing the ListBox:

    Private Sub CheckedListBox1_ItemCheck(sender As Object, e As ItemCheckEventArgs) Handles CheckedListBox1.ItemCheck
        Dim item = CheckedListBox1.Items(e.Index)
    
        If e.NewValue = CheckState.Checked Then
            ListBox1.Items.Add(item)
        Else
            ListBox1.Items.Remove(item)
        End If
    End Sub
    

    The issue with that is that the items will appear in the ListBox in the order you checked them, rather than the order they appear in the CheckedListBox. The other options keep the items in the same order in both lists.