Example 2: Drawing Items with Variable Width and Height
Here's another example. The items you create don't all have to be the same width and height. To create an owner-drawn list or combo box with variable item heights and widths, set the
DrawMode property to
OwnerDrawVariable. Then, implement a method that handles the MeasureItem event, which accepts a
sender (Object), and a System.Windows.Forms.MeasureItemEventArgs argument. The sample form frmColorListBox displays all the known system colors and their names in a combo box. The items themselves vary between 20 and 40 pixels in height. It's contrived and ugly (see
Figure 2), but serves to illustrate the point.
 | |
| Figure 2: The frmColorCombo form contains an owner-draw ListBox that displays all the known color names, accompanied by a variable-height color swatch. |
In .NET, the common colors are defined as an enumeration. Enumerations expose a getNames method that, given a Type object for a particular enumeration, returns an array of names in that enumeration. In this case, you want not only the names, but the colors themselves. You can create a Color object if you know the name by using the Color.FromName method. So the following For Each loop retrieves the known color names, and then adds Color objects to the combobox's Items collection.
Dim aColorName As String
For Each aColorName In _
System.Enum.GetNames _
(GetType(System.Drawing.KnownColor))
colorCombo.Items.Add(Color.FromName(aColorName))
Next
The frmColorCombo class defines a private Random object (mRand). The ComboBox control calls the MeasureItem event before drawing each item.
Protected Sub colorCombo_MeasureItem( _
ByVal sender As Object, ByVal e As _
System.Windows.Forms.MeasureItemEventArgs) _
Handles colorCombo.MeasureItem
e.ItemHeight = mRand.Next(20, 40)
End Sub
In the sample, the comboColor_MeasureItem event handler calls the overloaded Random.Next method to get the next random number between 20 and 40, and assigns that to the ItemHeight property of the MeasureItemEventArgs parameter.
The DrawItem event handler here is very similar to the one in the previous example. It retrieves the Color object from the Item list as specified by the Index value of the DrawItemEventArgs parameter, and then retrieves the color name from that Color object. The method draws a square and fills it with the appropriate color, and then draws the color name to the right of the square. As you can see, the DrawItem method uses the bounds set in the MeasureItem method for each item.
Protected Sub colorCombo_DrawItem( _
ByVal sender As Object, _
ByVal e As System.Windows.Forms.DrawItemEventArgs) _
Handles colorCombo.DrawItem
If e.Index < 0 Then
e.DrawBackground()
e.DrawFocusRectangle()
Exit Sub
End If
' Get the Color object from the Items list
Dim aColor As Color = _
CType(colorCombo.Items(e.Index), Color)
' get a square using the bounds height
Dim rect As Rectangle = New Rectangle _
(2, e.Bounds.Top + 2, e.Bounds.Height, _
e.Bounds.Height - 4)
Dim br As Brush
' call these methods first
e.DrawBackground()
e.DrawFocusRectangle()
' change brush color if item is selected
If e.State = _
Windows.Forms.DrawItemState.Selected Then
br = Brushes.White
Else
br = Brushes.Black
End If
' draw a rectangle and fill it
e.Graphics.DrawRectangle(New Pen(aColor), rect)
e.Graphics.FillRectangle(New SolidBrush _
(aColor), rect)
' draw a border
rect.Inflate(1, 1)
e.Graphics.DrawRectangle(Pens.Black, rect)
' draw the Color name
e.Graphics.DrawString(aColor.Name, _
colorCombo.Font, br, e.Bounds.Height + 5, _
((e.Bounds.Height - colorCombo.Font.Height) _
\ 2) + e.Bounds.Top)
End Sub
In the sample form, when you select a color from the frmColorCombo window, the main form changes the button color to reflect the choice. If you close the frmColorCombo window without selecting a color, the main form changes the button back to its default color.
You have complete control over the contents of ListBoxes and ComboBoxes within the .NET framework. You can extend the owner-draw techniques shown here to create complex interactive combo boxes such as those used in Office applications.