Results 1 to 17 of 17

Thread: [RESOLVED] Loop Listbox that was populated with it's DataSource and DisplayMember properties?

  1. #1

    Thread Starter
    Junior Member
    Join Date
    May 2016
    Posts
    21

    Resolved [RESOLVED] Loop Listbox that was populated with it's DataSource and DisplayMember properties?

    VB.ET, 2012, framework 3.5
    How does one loop through the items in a Listbox when the Listbox has been populated using it's DataSource and DisplayMemebr properties?

    In the example below, the upper loop does not work. The Debug line writes out "ListboxTest.Form1+Person". I need the items like "Bob" and "Paul"

    In the example below, the lower loop works correctly. How can one write the upper loop to give the same result as lower loop?


    Code:
    Public Class Form1
    
        Private People As New List(Of Person)
    
        Private Class Person
            Public Property Name As String
        End Class
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    
            People.Add(New Person With {.Name = "Bob"})
            People.Add(New Person With {.Name = "Paul"})
    
            Me.ListBox1.DataSource = People
            Me.ListBox1.DisplayMember = "Name"
    
            ' loop below writes out "ListboxTest.Form1+Person" instead of the "Bob"
            ' how does one iterate a Listbox that has been populated using it's DataSource and DisplayMember properties?
            For i As Integer = 0 To Me.ListBox1.Items.Count - 1
                Debug.WriteLine(Me.ListBox1.Items(i))
            Next
    
    
            Me.ListBox2.Items.Add("Bob")
            Me.ListBox2.Items.Add("Paul")
            ' loop below works as expected
            For i As Integer = 0 To Me.ListBox2.Items.Count - 1
                Debug.WriteLine(Me.ListBox2.Items(i)) ' need the loop above to work like this?
            Next
    
        End Sub
    End Class

  2. #2
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Location
    South Louisiana
    Posts
    11,715

    Re: Loop Listbox that was populated with it's DataSource and DisplayMember properties

    No need to loop through the Items since you have access to the List:
    Code:
    For i As Integer = 0 To People.Count - 1
        Debug.WriteLine(People.Items(i).Name)
    Next
    I would also like to point out that there's no need for a List in this instance since the class only has a single property.
    "Code is like humor. When you have to explain it, it is bad." - Cory House
    VbLessons | Code Tags | Sword of Fury - Jameram

  3. #3

    Thread Starter
    Junior Member
    Join Date
    May 2016
    Posts
    21

    Re: Loop Listbox that was populated with it's DataSource and DisplayMember properties

    Quote Originally Posted by dday9 View Post
    No need to loop through the Items since you have access to the List:
    I need to programmatically select an item on the list. But at this point I can't 'Select' anything because I can't read through the text items (on the list itself) I need to find a string that matches an item in the ListBox and then programmatically select that item on the ListBox

  4. #4
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,464

    Re: Loop Listbox that was populated with it's DataSource and DisplayMember properties

    Code:
    ListBox1.SelectedIndex = ListBox1.FindStringExact("text to find")

  5. #5

    Thread Starter
    Junior Member
    Join Date
    May 2016
    Posts
    21

    Re: Loop Listbox that was populated with it's DataSource and DisplayMember properties

    Thanks that helps but. I need to be able to find and select an item that only has part of the text in the listbox too. There isn't always going to be an exact match or a match that 'starts with' the search string.

    I envisioned it looking something like below, the code below is not syntactically correct


    Code:
            For i As Integer = 0 To Me.ListBox1.Items.Count - 1
                If Me.ListBox1.Items(i).IndexOf("SearchString") > -1 Then
    
                End If
            Next

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

    Re: Loop Listbox that was populated with it's DataSource and DisplayMember properties

    ListBoxes do not hold Strings. This is a lesson every VB .NET developer has to learn at some point.

    ListBoxes hold Objects that they display as Strings. To do that, they will by default call .ToString() on the Objects they hold. Or, if you set the 'DisplayMember' property, they will look for that property on the Object and call .ToString() on that.

    So you might, for some reason, decide to put some Button controls inside a ListBox's Items. What will happen is, instead of displaying 10 buttons, you will get 10 lines of "System.Windows.Forms.Button". That is what Button.ToString() returns. But if you set 'DisplayMember' to "Name", then the Name of each Button will be displayed.

    So while it LOOKS LIKE the ListBox is a control for holding Strings, the reality is it's a control for holding anything but representing those things as Strings. This has implications on how you interact with it when it's not holding Strings. If you set DataSource, it's most definitely not holding Strings. In your case, it's holding your Person class that you wrote. And since DisplayMember is set to "Name", it displays the value of each Person's Name property.

    Let's break apart what happens to make your line of code print "ListboxTest.Form1+Person".
    Code:
    Debug.WriteLine(Me.ListBox2.Items(i))
    'ListBox2.Items(i)' is some instance of the Person class. It is being passed to Debug.WriteLine(). When WriteLine() gets an Object, it needs to convert it to a String. So it calls .ToString() on that object. By default, .ToString() returns the name of the class.

    So why does your second loop work? Well, look at what you add:
    Code:
    Me.ListBox2.Items.Add("Bob")
    Me.ListBox2.Items.Add("Paul")
    If you put Strings in, what you will get out are Strings, so that explains why it works.

    If you want the name, you have to write code like this:
    Code:
    Dim p As Person = CType(Me.ListBox.Items(i), Person)
    Debug.WriteLine(p.Name)
    See what it's doing? It gets the object out of the ListBox's items, then converts it to a Person since it's considered 'Object' at that point. Then, it prints the Person's Name property.

    But, you can also leverage the fact that you already have the list of Person objects:
    Code:
    Me.ListBox1.DataSource = People
    So you could also write the above as:
    Code:
    Dim p As Person = People(i)
    Debug.WriteLine(p.Name)
    It's generally easier to do that because you don't have to cast.

    So, when the user selects an item in the list:
    • SelectedItem will be a Person. If you want its Name, you will have to cast it from Object to Person, then access the 'Name' property.
      Code:
      Dim selectedPerson As Person = CType(ListBox1.SelectedItem, Person)
      Debug.WriteLine(selectedPerson.Name)
    • SelectedIndex will be the index of the selection. You can use that to either get an item you will need to cast from the ListBox, or directly index the data source:
      Code:
      Dim selectedPerson As Person = CType(ListBox1.Items(ListBox1.SelectedIndex), Person)
      Debug.WriteLine(selectedPerson.Name)
      
      - OR -
      
      Dim selectedPerson As Person = People(ListBox1.SelectedIndex)
      Debug.WriteLine(selectedPerson.Name)


    If you want to find a person with a name given by a user, .paul.'s #4 shows that off. The .FindStringExact() method looks for the first item that is displaying the indicated text, and returns its index. If you set SelectedIndex to that index, you will select the item. There's a handful of other ways, but this one's sensible enough.enough
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

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

    Re: Loop Listbox that was populated with it's DataSource and DisplayMember properties

    Argh. Quit adding features as time goes on. If you'd asked every question in the first post, someone could answer all at once. But when you ask part of the question, then reveal the next part, then reveal the next part, we all have to spend more and more time on the thread.

    So you want to do a partial string search. FindStringExact() won't work, because as it says it looks for exactly the same name. We could do something hard, or we could take a trip to the documentation. I turns out there's a FindString() that works the same way, but looks for items with strings that start with the given string.

    If that doesn't work, if you want to look INSIDE strings, think about why the code you tried didn't work. Remember, your ListBox contains Person objects:
    Code:
    If Me.ListBox1.Items(i).IndexOf("SearchString") > -1 Then
    'Items(i)' returns a Person as an Object. Object does not have an IndexOf() method. Person probably doesn't have an IndexOf() method. You want, and need, to get at the Person's name property. So the proper loop to select the first item that matches some bit of the string would be:
    Code:
    For i As Integer = 0 To People.Count ' Maybe .Length, maybe .Count(), you get the picture.
        Dim thisPerson As Person = People(i)
        If thisPerson.Name.IndexOf("SearchString") > -1 Then
            ListBox1.SelectedIndex = i
            Exit For
        End If
    Next
    This is gluing small problems together to solve a big problem. "I want to select the Person that matches this text." To do that, we answer:
    • How do I tell if a Person matches the text? (.IndexOf() called on the Name.)
    • How do I tell what index that person is? (The loop variable 'i'.)
    • How do I select an item in a ListBox? (The SelectedIndex property.)

    You probably knew how to do all of those things, it's just a matter of gluing them together in the right order!
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  8. #8

    Thread Starter
    Junior Member
    Join Date
    May 2016
    Posts
    21

    Re: Loop Listbox that was populated with it's DataSource and DisplayMember properties

    Quote Originally Posted by Sitten Spynne View Post
    Code:
    For i As Integer = 0 To People.Count ' Maybe .Length, maybe .Count(), you get the picture.
        Dim thisPerson As Person = People(i)
        If thisPerson.Name.IndexOf("SearchString") > -1 Then
            ListBox1.SelectedIndex = i
            Exit For
        End If
    Next
    That gave me what I needed, thanks a bunch!

    This is what I arrived at (below), please, let me know if it can be improved?


    Code:
    Public Class Form1
    
        Private People As New List(Of Person)
    
        Private Class Person
            Public Property Name As String
        End Class
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    
            People.Add(New Person With {.Name = "Bob"})
            People.Add(New Person With {.Name = "Paul"})
            People.Add(New Person With {.Name = "John"})
            People.Add(New Person With {.Name = "Annie"})
            People.Add(New Person With {.Name = "Suzy"})
            People.Add(New Person With {.Name = "Roger"})
            People.Add(New Person With {.Name = "Bluzy"})
    
            Me.ListBox1.DataSource = People
            Me.ListBox1.DisplayMember = "Name"
            Me.ListBox1.SelectedIndex = -1
    
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Dim pplCount As Integer
    
            Select Case Me.ListBox1.SelectedIndex
                Case -1, Me.ListBox1.Items.Count - 1
                    pplCount = 0 ' start search at top
    
                Case Else
                    pplCount = Me.ListBox1.SelectedIndex + 1 ' start search after SelectedIndex
    
            End Select
    
            Do Until pplCount = People.Count
                Dim thisPerson As Person = People(pplCount)
                If thisPerson.Name.ToUpper.IndexOf(Me.TextBox1.Text.ToUpper) > -1 Then
                    Me.ListBox1.SelectedIndex = pplCount
                    Exit Sub
                End If
                pplCount += 1
            Loop
    
        End Sub
    End Class

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

    Re: Loop Listbox that was populated with it's DataSource and DisplayMember properties

    I like it! If it were me, I'd have written it with some helper methods, but that's a matter of style, not function.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  10. #10
    Smooth Moperator techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,532

    Re: Loop Listbox that was populated with it's DataSource and DisplayMember properties

    eeehhh


    explain this logic to me:
    Code:
            Dim pplCount As Integer
    
            Select Case Me.ListBox1.SelectedIndex
                Case -1, Me.ListBox1.Items.Count - 1
                    pplCount = 0 ' start search at top
    
                Case Else
                    pplCount = Me.ListBox1.SelectedIndex + 1 ' start search after SelectedIndex
    
            End Select
    
            Do Until pplCount = People.Count
                Dim thisPerson As Person = People(pplCount)
                If thisPerson.Name.ToUpper.IndexOf(Me.TextBox1.Text.ToUpper) > -1 Then
                    Me.ListBox1.SelectedIndex = pplCount
                    Exit Sub
                End If
                pplCount += 1
            Loop
    Let's say I select the second item in the list... so .SelectedIndex = 1

    so it goes into the case... and drops into the else ... pplCount now equals 2...

    then it starts the loop... pplCount is less than PEople.Count.... enters the loop...it then gets the second item in the list... it compares that to the text of the list box, which of course matches... so it iset the .SelectedIndex (which WAS 1) to pplCount (so now it's 2 - so the selection has changed!) ... and then it bails... whaaaa?

    That's nothing like the loop that Sitten posted...

    Honestly, I've looked this thread over a couple times... I'm at a loss as to what hte problem is exactly... I see the attempts at doing something, but I'm not sure I've seen a coherent explanation of the WHAT needs to be done. There's a lot of HOW which... I'm not sure I truly understand the intent/requirements here...

    It sounds like what hte OP is trying to do, is based on what is selected in a bound listbox, do something with the bound object... am I close? or way off base? And if you do want to do something with it, what?

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

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

    Re: Loop Listbox that was populated with it's DataSource and DisplayMember properties

    Hmm. You're making me doubt. Let me see if I still believe it works.

    I think the implied goal is: "When you click this button, search for the first item in the listbox that has some of the text within it, case-insensitive. If an item is selected, search for the /next/ matching item."

    Does it accomplish that?

    Let's say nothing's selected and there's 3 people. SelectedIndex will be -1. So pplCount gets set to 0 in the Case statement. Next, the Do..Until executes because pplCount is not equal to People.Count. The Person at index 0 is inspected. If that Person's Name property (a String) contains the uppercase text of TextBox1, the SelectedIndex is set to 0 and the Sub is terminated. The end result would be "Select item 0, because it contains the text." If that item doesn't contain the text, the next iteration checks item 1. That one will either be selected or item 2 will be queried. If that one is not selected, pplCount = People.Count and the loop terminates.

    So let's say you've selected item 1, and there's 4 people. SelectedIndex will be 1. So pplCount will be set to 2. The person at index 2 is inspected, if it contains the text it will be selected. If it does not, the person at index 3 will be inspected. If that matches, it is selected, and if not the index advances to 4, which is People.Count and the Sub terminates, leaving item 1 selected.

    That seems to accomplish the goal. Your confusion is why I suggested, "Ask the whole question at once." This code doesn't really do exactly what he's asked in terms of questions, but I approved it because it does do a sensible thing and seems to cover every case.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  12. #12
    Smooth Moperator techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,532

    Re: Loop Listbox that was populated with it's DataSource and DisplayMember properties

    Ahhh... ok... that makes sense then... somehow I missed the "select the next matching item in the list" bit...

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

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

    Re: Loop Listbox that was populated with it's DataSource and DisplayMember properties

    It wasn't explicitly stated, but I figured it out from looking over the code.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  14. #14
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Location
    South Louisiana
    Posts
    11,715

    Re: Loop Listbox that was populated with it's DataSource and DisplayMember properties

    I actually backed out of the thread after the:

    *I need this
    **No actually I need this
    ***No actually I really need this

    I still don't know what the actual question is.
    "Code is like humor. When you have to explain it, it is bad." - Cory House
    VbLessons | Code Tags | Sword of Fury - Jameram

  15. #15

    Thread Starter
    Junior Member
    Join Date
    May 2016
    Posts
    21

    Re: Loop Listbox that was populated with it's DataSource and DisplayMember properties

    Originally I was simply asking how to loop through the items in a Listbox. A Listbox that was populated using the Listbox's DataSource and DisplayMember properties. I strayed off this original question because, as pointed out by another, there was no reason to loop through the 'Items' in a Listbox because the code in my original post had access to the Listbox's underlying Datasource List, People. At that moment I still hadn't realize how this List of Person, or People could be used to help select Items on the Listbox. In all the excitement I added new features and messed the question up. For that, I apologize sincerely. I truly appreciate the help I received here today!

    Ultimately I was indeed trying to Find Items in a Listbox that contained certain text, then find the next item that contained certain text and so on.

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

    Re: [RESOLVED] Loop Listbox that was populated with it's DataSource and DisplayMember

    Yeah, it feels sort of like there's a dogpile, but it is important to learn: just ask the whole question up-front!

    What happened in this thread happens a lot: someone has a problem, tries a solution, and it doesn't work but they feel close. What they don't know is they're on the wrong track. They post a thread asking how to make that solution work, and the only real answer the forums can give is "It won't, what are you trying to do?" But when you don't know what you don't know, it's hard to know you're supposed to ask more.

    So to avoid that, when I ask a question I like to structure it like this:

    I'm trying to make a form that lets me search a listbox for particular items. The ListBox is bound to a Person class with a Name property that's set to the Display member.

    To do this I tried...

    I expected...

    But instead...

    [Optional] I also tried <brief description>, but had trouble too. What am I missing?
    That flows well. Problem statement -> attempted solution -> expected results -> actual results. A lot of times, when I start typing out the expected results, I figure out what's wrong with the thing I tried, because in the process of making a paragraph I realize what I'm saying doesn't look like what my code does at all!
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  17. #17
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Location
    South Louisiana
    Posts
    11,715

    Re: [RESOLVED] Loop Listbox that was populated with it's DataSource and DisplayMember

    Quote Originally Posted by Sitten Spynne View Post
    A lot of times, when I start typing out the expected results, I figure out what's wrong with the thing I tried, because in the process of making a paragraph I realize what I'm saying doesn't look like what my code does at all!
    I second that!
    "Code is like humor. When you have to explain it, it is bad." - Cory House
    VbLessons | Code Tags | Sword of Fury - Jameram

Tags for this Thread

Posting Permissions

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



Click Here to Expand Forum to Full Width