-
May 26th, 2016, 11:34 AM
#1
Thread Starter
Junior Member
[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
-
May 26th, 2016, 11:46 AM
#2
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.
-
May 26th, 2016, 11:58 AM
#3
Thread Starter
Junior Member
Re: Loop Listbox that was populated with it's DataSource and DisplayMember properties
Originally Posted by dday9
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
-
May 26th, 2016, 12:03 PM
#4
Re: Loop Listbox that was populated with it's DataSource and DisplayMember properties
Code:
ListBox1.SelectedIndex = ListBox1.FindStringExact("text to find")
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
May 26th, 2016, 12:21 PM
#5
Thread Starter
Junior Member
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
-
May 26th, 2016, 12:29 PM
#6
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.
-
May 26th, 2016, 12:36 PM
#7
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.
-
May 26th, 2016, 01:32 PM
#8
Thread Starter
Junior Member
Re: Loop Listbox that was populated with it's DataSource and DisplayMember properties
Originally Posted by Sitten Spynne
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
-
May 26th, 2016, 01:46 PM
#9
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.
-
May 26th, 2016, 02:40 PM
#10
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
-
May 26th, 2016, 02:57 PM
#11
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.
-
May 26th, 2016, 03:21 PM
#12
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
-
May 26th, 2016, 03:56 PM
#13
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.
-
May 26th, 2016, 03:57 PM
#14
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.
-
May 26th, 2016, 10:10 PM
#15
Thread Starter
Junior Member
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.
-
May 27th, 2016, 09:16 AM
#16
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.
-
May 27th, 2016, 09:51 AM
#17
Re: [RESOLVED] Loop Listbox that was populated with it's DataSource and DisplayMember
Originally Posted by Sitten Spynne
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!
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|