Collection Methods and Properties
My biggest beef with list boxes is that although they look and act like collections, they’re not quite collections. For one thing, they’re zero-based instead of one-based. For another, they have the wrong property and method names—ListCount, List, AddItem, and RemoveItem instead of Count, Item, Add, and Remove. Furthermore, they don’t work with For Each.
You can curse the darkness or you can light a candle. I did both. The XListBoxPlus control has one-based collection methods and properties. It looks and works like a collection.
The design of XListBoxPlus is more interesting than its code. This class tries to combine the best features of list boxes and collections, keeping in mind that list boxes can’t work quite the same way as collections work. The biggest difference is that list boxes have a selected item, and collections don’t. Other differences are simply limitations of list boxes—limitations that XListBoxPlus attempts to eliminate. Table 11-1 compares what you can do with a list box, a collection, and a sorted list box (represented by lst, n, and srt, respectively).
Operation |
ListBox |
Collection |
XListBoxPlus |
Get item 3 |
s = lst.List(2) |
s = n.Item(3) |
s = srt.Item(3) |
Get "Pig" index |
Can’t do it |
Can’t do it |
i = srt("Pig") |
Select "Pig" |
lst.Text = "Pig" |
Undefined |
srt.Text = "Pig" |
|
|
|
srt.Current = "Pig" |
Change item 3 |
lst.List(2) = "Dog" |
Can’t do it |
srt.Item(3) = "Dog" |
Change "Dog" |
Can’t do it |
Can’t do it |
srt("Dog") = "Cat" |
Select item 3 |
lst.ListIndex = 2 |
Undefined |
srt.Current = 3 |
Get index |
i = lst.ListIndex |
Can’t do it |
i = srt.Current |
Get selected |
s = lst.Text |
Undefined |
s = srt.Text |
Add "Cat" |
lst.AddItem "Cat" |
n.Add "Cat" |
srt.Add "Cat" |
Remove item 3 |
lst.RemoveItem 2 |
n.Remove 3 |
srt.Remove 3 |
Remove "Pig" |
Can’t do it |
n.Remove "Pig" |
srt.Remove "Pig" |
Iterate by item |
Can’t do it |
For Each v in n |
For Each v in srt |
Iterate by index |
For i = 0 To _ |
For i = 1 To _ |
For i = 1 To _ |
|
lst.ListCount –1 |
n.Count |
srt.Count |
Table 11-1. List box and collection operations.
Most of these operations are clear once you understand list boxes and collections, but a few bear further study. I programmed with list boxes for years before I understood two of their more useful, but obscure, features. I knew that the Text property was important for combo boxes, but I didn’t know it even existed for list boxes. I always wrote this redundant code to access the selected item:
s = lst.List(lst.ListIndex)
Every time I wrote it I cursed the authors of the ListBox control for requiring such an ugly syntax, and I took a little jab at them in the first edition of this book. Well, I like my crow with catsup. Here’s what you can do instead:
s = lst.Text
The Text property can also be used to look up an item. (Yum! Feathers and all.) You can select the Crow item with this syntax:
lst.Text = "Crow"
If there is no Crow item, you’ll deselect whatever is currently selected (ListIndex = –1). The lookup is case insensitive (crow finds Crow), but complete (Cro doesn’t find Crow).
This is cool, but the XListBoxPlus is even more so. You can index by number or by string value. It works kind of like collections, but
i = n("Pig")
and
i = srt("Pig")
don’t mean exactly the same thing. Indexed collections return objects, as explained later in this chapter in “Sorted Collections,” but sorted list boxes contain strings, not objects. Indexing has to mean something different.
I made the default Item property return a numeric index if you pass a string, or a string if you pass an index. Purists might object to a property returning different types for different arguments, but it works in this case.
Here are few other points for users of the XListBoxPlus class:
-
Properties that are read-only at design time are the bane of the control delegator. I couldn’t figure out a way to delegate the cool new CheckBox style, the MultiSelect property, or the IntegralHeight property.
-
There’s no way to duplicate the neat little drop-down editing box that you get for the List and ItemData properties. XListBoxPlus uses a property page instead.
-
In sorted mode, you can have only one copy of each item. I could have designed the class to allow duplicate entries, but that doesn’t make much sense for sorted items.
-
When no item is selected, the Index property is 0 rather than –1. This makes for easier conditional testing. You can also set Index to 0 to select nothing.
CHALLENGE I’d like to have a sorted version of the FileListBox control, but couldn’t create one by delegating because the original control doesn’t allow addition or removal of items. Technically, you don’t need to add or remove items to sort a list box, but you do need to exchange items, and that can’t be done with a FileListBox control because nothing can be assigned to List items. You could, however, design a class to make an internal list box look and act like a FileListBox control, except that it could be sorted by date, name, extension, or attributes. To do this, you would use the Dir function to reload the list box in the current sort order at appropriate times. I’ve always wanted a file list box like that, and the only reason I didn’t create one for this book is that I can do most of what I want with the ListView control. But the ListView has its problems, so you might want to use XListBoxPlus as a model for your own XFileListPlus control.