In an effort to get rid of VB6.Get/SetItemData from a VB6 project upgraded to .NET, the project has been changed to use custom object classes (e.g., with Name and Data members) in collections. This works fine, but has the performance-overhead and type-unsafety arising from the ListBox.Items member being a generic ObjectCollection.
What would be better is to create a subclass of a Listbox that is exactly the same as a normal one, except with a type-safe collection for the Items member instead of a generic object collection; that is Items should be a System.Collections.Generic.List(Of SomeType) rather than just an ObjectCollection.
I have spent several hours trawling through MDSN, VB Help and the internet, but everybody seems to suggest different methods, such as abusing "shadowing" (because Items is not overridable), overriding the CreateItemCollection() method, or using a DataSource (not applicable, because apparently, it makes Add() and Remove() methods stop working).
Being new to .NET, I would like to know what the "proper" way to do this is. Would somebody please tell me

What is the proper way to change what ListBox.Items holds?
Aaron Steers
Hey martin, you might be interested in Expert VB 2005 Business Objects
check this search
jswilson
Thanks to all who assisted and all those out there who post code examples to help each other out.
Martin Howe
23rd June 2006
Hayder Marzouk
DataList.Add(something)
ListBox1.DataSource = Nothing
ListBox1.DataSource = Things
DataList.RemoveAt(somenumber)
ListBox1.DataSource = Nothing
ListBox1.DataSource = Things
This is not optimal and there is a way to suspend then restore binding, but the documentation for that is highly detailed and will take a while to understand since it doesn't give an overall worked example for non-database data; however, this ought to be good enough for a small list of items that is modified infrequently.
To save others the work I had to do to find this out, a small working example program can be downloaded here if anyone wants it: http://www.martinsobservationpost.net/public/BindingExperiments.zip It is nothing fancy, just a small form to demonstrate the principle.
Fab IT
Just so anybody else considering doing this is aware of it, there are two problems that have to be overcome. One is that when an empty ListBox updates itself to add a [first] item in response to the List adding a first item, the ListBox selects the item. The other is that when the last item in the List is removed and the ListBox updates itself accordingly, the ListBox makes the next item down become selected, even if it was not selected before.
To deal with the first problem, use something like this:
Things.Add(New Thing(EnterThingName.Text, CInt(EnterThingData.Text)))
ThingsListing.SetSelected(Things.Count - 1, False)
To deal with the second use something like this:
Dim ItemIndex As Integer = ThingsListing.SelectedIndex
Dim WasSelected As Boolean = False
If ItemIndex > 0 AndAlso ThingsListing.GetSelected(ItemIndex - 1) Then
WasSelected = True
End If
Things.RemoveAt(ItemIndex)
If ItemIndex > 0 And Not WasSelected Then
ThingsListing.SetSelected(ItemIndex - 1, False)
End If
Finally, the list itself is not sorted, the way a ListBox is. I found an example on GotDotNet of how to make a sorted list of a specific type and have, after much trial and error, created from that a sorted generic Binding List class. I'll clean it up and post a link to it tomorrow, in case it helps out somebody else in the same position, then mark this question as answered.
reZer
set datasource to your generic collection, perform operations on the collection, not list box.items.
then you can do this:
The controls is just a presentation for your data structure. don't use it as your data structure.
Here's a good place to start: Data Binding and Windows Forms
Also dig into this: Providers of Data to Windows Forms
but the key is - Manipulate the structure the control is bound to, do not, i repeat do not use your control as a data structure. That was wrong in VB6 as well (albeit databinding in VB6 wasn't that friendly. . . still waiting for someone to explain how VB6 became so popular. Man, what a dog!)
sp_412000
sorry. . . bad typing. . . Ive been doing alot of that lately!!!
should have said BindingList (of MyClass)
yennisse
As it happens, the list in question wasn't bound to anything and while that particular list really was used to manipulate data that it visually represented, the original author of this code often used various list-oriented controls, hidden off the edge of the form where they couldn't be seen, purely for their data structures (shudder).
EDIT: Looks like I spoke too soon. The line dim myItems as new ListBox(Of MyClass) in the above example says that dimming a ListBox with a type is illegal. Using this:
Private ImportList As New System.Collections.Generic.List(Of FlaggedListItem)
List1.DataSource = ImportList
seems to work at first, but the ListBox List1 does not update when ImportList is modified; in fact, after adding two items to ImportList (and confirming in the debugger), List1 is empty! I did look at the references given, but they are all very database-orientated and are very heavy going for a newcomer to databinding. Can anyone give a link to a working example of a ListBox control being used to mirror an array or collection; something I can pick apart and learn from that is relevant to simple collections, not databases Surely somebody must have done this before