dcsimg
Results 1 to 8 of 8

Thread: Check if Listbox contains item

  1. #1

    Thread Starter
    Lively Member dprontnicki's Avatar
    Join Date
    Sep 2016
    Posts
    101

    Check if Listbox contains item

    Hi,

    I have two listboxes, one is a select from and the other is a queue. The user can select objects from the first listbox and add them to the second (queue). I am trying to keep the user from adding the same item twice so I added an If statement. But it does not seem to be working. I think because my listboxes are not just text. They are displaymember and valuemember. But I don't THINK it should matter. I have tried different variations of the code below with no luck. I know it has to be something simple I am missing. Any help would be appreciated.

    Code:
    Private Sub btnAddToQueue_Click(sender As Object, e As EventArgs) Handles btnAddToQueue.Click
    
            If lstQueue.Items.ToString.Contains(lstSelectDetail.SelectedItem.ToString) = True Then
    
                'Initiate error message box
                Dim msg = ("Detail already exists in queue, please select another detail.")
                Dim title = "Error Adding Detail to Queue"
                Dim style = MsgBoxStyle.Information
    
                MsgBox(msg, style, title)
    
            Else
    
                For Each detail As FileDetail In lstSelectDetail.SelectedItems
                    lstQueue.Items.Add(detail)
                Next
    
            End If
    
        End Sub

  2. #2
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,580

    Re: Check if Listbox contains item

    You got things a little bit mixed up, but the fix is easy! One thing that makes life easier is if you don't try to do too many things on one line. What do I mean? Well, let's take this line and see what happens if we turn it into more lines:

    Code:
    If lstQueue.Items.ToString.Contains(lstSelectDetail.SelectedItem.ToString) = True Then
    Every property access and method call in there could be separated onto a new line. Let's see what happens if we do that.
    Code:
    Dim queueItems = lstQueue.Items
    Dim queueItemsString = queueItems.ToString()
    Dim selectedItem = lstSelectDetail.SelectedItem
    Dim selectedItemString = selectedItem.ToString()
    
    If queueItemsString.Contains(selectedItemString) Then
    This is enough to see the problem. Can you figure it out? Try adding it in and using a debugger to see what queueItemsString is. It's probably "{System.Windows.Forms.ListBox+ListBoxItemsCollection}". That's not what you expected, is it?

    The problem is you called .ToString() on the collection! And since String happens to have a .Contains() method, you don't get an error when you try to check if items are within that. What we want is, "If the selected item is already in lstQueue..." Here's code that reflects that:
    Code:
    Dim queueItems = lstQueue.Items
    Dim selectedItemString = lstSelectDetail.SelectedItem.ToString()
    
    If queueItems.Contains(selectedItemString) Then
        ...
    I did jam a couple of things on the same line in this one, but I think you'll agree it's still clear what it is based on the name!

  3. #3

    Thread Starter
    Lively Member dprontnicki's Avatar
    Join Date
    Sep 2016
    Posts
    101

    Re: Check if Listbox contains item

    Thank you so much! I really appreciate the explanation. It makes a lot of sense. But...

    I am still able to add the same item. queueItems is System.Windows.Forms.Listbox.ObjectCollection.

    I added a pic of debug.

    Name:  Debug.jpg
Views: 2939
Size:  29.0 KB

  4. #4
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,580

    Re: Check if Listbox contains item

    Hm. I'm pretty sure that works. Here's some quick code for a project with 2 list boxes, a button, and the kind of functionality you're requesting:

    Public Class Form1

    Private Sub WhenFormIsShown(sender As Object, e As EventArgs) Handles Me.Shown
    ListBox1.Items.AddRange({"one", "two", "three"})
    End Sub


    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim selectedItem = ListBox1.SelectedItem

    If ListBox2.Items.Contains(selectedItem) Then
    MessageBox.Show("Nope.")
    Else
    ListBox2.Items.Add(selectedItem)
    End If
    End Sub
    End Class
    So if the code you're using is analagous, there's a few things that could be true. Maybe the things in the list boxes aren't strings. Maybe they aren't exactly equal, which can be true if spaces are involved. But I can't check those things for you, you'll have to poke at them in the debugger to figure out what's goign on.

  5. #5
    PowerPoster
    Join Date
    Oct 2010
    Posts
    2,141

    Re: Check if Listbox contains item

    Quote Originally Posted by dprontnicki View Post
    .... I think because my listboxes (items)are not just text.
    Then why are you treating the listbox items as text?

    This:
    Code:
    For Each detail As FileDetail In lstSelectDetail.SelectedItems
    indicates that you know the items is of type FileDetail. It also indicates that you can have multiple items selected. Just loop through the selected items and add the item if it is not in lstQueue.Items.

    Code:
    For Each detail As FileDetail In lstSelectDetail.SelectedItems
       If Not lstQueue.Items.Contains(detail) Then lstQueue.Items.Add(detail)
    Next
    Last edited by TnTinMN; Jan 4th, 2017 at 02:30 PM. Reason: corrected code sample

  6. #6

    Thread Starter
    Lively Member dprontnicki's Avatar
    Join Date
    Sep 2016
    Posts
    101

    Re: Check if Listbox contains item

    TnTinMN,

    If Not lstQueue.Items.Contains produces an error on Contains. ArgumentNullException - Argument not specified for parameter 'value' of 'Public Overloads Function Contains (value of object) as Boolean'.

  7. #7
    PowerPoster
    Join Date
    Oct 2010
    Posts
    2,141

    Re: Check if Listbox contains item

    Quote Originally Posted by dprontnicki View Post
    TnTinMN,

    If Not lstQueue.Items.Contains produces an error on Contains. ArgumentNullException - Argument not specified for parameter 'value' of 'Public Overloads Function Contains (value of object) as Boolean'.
    I typed that in wrong, but you really should have been able to figure it out.

    Code:
    If Not lstQueue.Items.Contains(detail) Then lstQueue.Items.Add(detail)

  8. #8
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,580

    Re: Check if Listbox contains item

    Oh. OK, a couple of things here. I missed a tiny detail that's important.

    I think because my listboxes are not just text. They are displaymember and valuemember. But I don't THINK it should matter.
    For .Contains() to work, it needs to know how to tell if the things in the list are equal to the thing you're seeking. If you're seeking a String, and the list doesn't contain Strings, you can't find the thing. At all. And you can't really just call .ToString() on the item to make that work, you have to do a little more work to facilitate that.

    When you're using the DisplayMember/ValueMember properties, you might consider using SelectedValue instead of SelectedItem. That'll look at SelectedItem and use whatever property ValueMember tells it to use. Or it should, but right now I'm having trouble getting it to return anything but Nothing for me. Whatever. Here's an updated example:

    Code:
    Public Class Form1
    
        Private Sub WhenFormIsShown(sender As Object, e As EventArgs) Handles Me.Shown
            ListBox1.DisplayMember = "Display"
            ListBox1.ValueMember = "Value"
    
            ListBox2.DisplayMember = "Display"
            ListBox2.ValueMember = "Value"
    
            For i As Integer = 0 To 10
                ListBox1.Items.Add(New TestClass With {.Display = "Item" & i.ToString, .Value = i + 1})
            Next
        End Sub
    
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            ' Get the selected item, and quit if there's no selected item.
            Dim selectedItem = CType(ListBox1.SelectedItem, TestClass)
            If selectedItem Is Nothing Then
                Return
            End If
    
            ' Get the selected item's value.
            Dim selectedValue = selectedItem.Value
    
            ' doesContain will be True if ListBox2 contains an item with the same Value as selectedValue.
            Dim doesContain As Boolean = False
            For Each item As TestClass In ListBox2.Items
                If item.Value = selectedValue Then
                    doesContain = True
                    Exit For
                End If
            Next
    
            ' Only add the item if doesContain is False.
            If doesContain Then
                MessageBox.Show("Nope.")
            Else
                ListBox2.Items.Add(ListBox1.SelectedItem)
            End If
        End Sub
    End Class
    
    Public Class TestClass
        Public Property Display As String
        Public Property Value As Integer
    End Class
    I'm not sure why SelectedValue didn't work for me, but it's just as easy to ask SelectedItem for its Value property, if cast first. What happens next can get kind of tricky, and I can see some people that might claim I made it too complicated.

    .Contains(), in this simple case, would work. I could see if ListBox2.Contains(ListBox1.SelectedItem) because, as a side effect of this code, they're the same object. I can envision other cases where the objects in ListBox2 have the same values, but aren't the same as in ListBox1. That'd break Contains(). Newer .NET APIs have ways around this, but ListBox is old and never got updated, so it is what it is.

    So sometimes it's best to write your own Contains(), and do the comparison yourself. That's what I did. The For loop checks if ListBox2 has any item with a .Value property identical to the selected item's .Value property. Since these are Integers, we know what the '=' sign does is right.

    Depending on what your "TestClass" is, you'll have to do similar work.

    The error you mentioned means you passed Nothing to .Contains(), and it doesn't like that. SelectedItem is a property that can return Nothing, so you should make sure not to call .Contains() if it does. My new code's got that protection, my old code didn't.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width