I always wanted to use a multi-column ListBox in a way similar to the ListBox provided through Microsoft Access - several columns of information for which an entire row will get selected. Unfortunately the Visual Studios never saw it fit to add this- and it doesn't look like we'll get this in 2005 either from the VB Express Beta. Recently I was thinking of making controls and this one popped into my head. So, here is the control for you to enjoy.
There was one requirement that I wanted to put on it. I wanted the development environment to look at it as a
ListBox, so it had to be inherited from the
ListBox control. Now this at first was limiting on what you could do, because it essentially is a
ListBox. The biggest hurdle was the scrollbar. I had to override the
Paint method which eliminates the scrollbar and since it is inherited from a
ListBox, simply adding a scrollbar object will not work- so the scrollbar had to be completely drawn and handled by the code.
Using the control
The control resides in the namespace
CWControls - this is important for adding items at runtime. The use of the control is very simple once you've added it to your Toolbox. Add it to your form just like you do with any other control.
You'll notice several properties have been added. I'll go through each of these properties one by one:
This specifies the number of columns the
ListBox will show. This value cannot be less than 1. *Note*- you can have more columns stored in the
Items property than this number, then they just won't show.
This array specifies the width of the columns in the
ListBox. The last column displayed however, has an automatic width adjusted to the edge of the
ListBox. The unit is pixels. *Note*- make your
ListBox wide enough, I have not yet implemented horizontal scrolling.
This property is not available in the Properties window. It returns the entire selected row delimited by an optional delimiter (default is a space).
This property returns the
Text of the item - or column 1.
This property belonged to the original
ListBox - it now returns the
Value you set for an item.
Again this property was part of the
ListBox, it now returns the selected item as a
The meat of the matter.
Items is no longer an object type and just can't support anything going into it. It is of type
You'll notice that the
DrawMode property is still there. Yes I've implemented the different states of the
DrawMode property so that you can do your own drawing of the control.
You can edit
Items from the Properties window, but not like the string collections. The
Items consists of the following parts:
Value is never shown, but can be more useful than an Index value returned for searching in databases.
This is what is displayed in column 1 as the main item.
This is a dynamic string array. Put as many strings in here as you need for all your columns.
Here is a sample for adding items at runtime:
For i As Integer = 0 To max
Dim x As New CWControls.MCListBoxItem
x.Text = i
For t As Integer = 0 To 1
x.SubItems(t) = i & " - " & t
For those who are interested in the scrolling process, I'll let my code do the talking for the most part (sorry I'm not a great commenter). I'll explain a few parts here.
There are several parts that need to be drawn. Now while drawing you have to be aware of its state (Up, Down, or Hover). The items that need to be drawn are: Up arrow, Down Arrow, Thumb, Back.
The Up and Down arrows, along with the Thumb each have the three states mentioned above. The back has two states Normal or pressed.
In order to give it these states we need to watch the
OnMouseLeave events for Hover, and the
OnMouseUp events for Pressed (and selecting items) over the different parts of the scrollbar.
Originally I had the entire item list drawn at one time to a bitmap and saved for scrolling different parts into view at one time, however that proved to be too much for the control when there were hundreds of items. Here the control draws only what it needs and stores the current items shown in a buffer.
In order to scroll nicely, we need to use a separate thread that is terminated when
MouseUp is fired. Loops and global variables do that trick nicely. The thread itself is global, so it can put itself to sleep and we can have different scroll speeds (first item scrolling scrolls slower than that of multiple).
MouseMove also helps us in scrolling by selecting and dragging the thumb. To see how it was done, look into the region with the label "UI Handlers - Scrolling".
I hope you find this control useful, whether you're using the control or are just interested in the scrolling example. I had fun writing it (and trying to figure out how to do the various parts).
JumpScroll methods to fix the scrolling issue while scrolling past the end/beginning of the list by clicking the scrollbar background.