Make an owner-drawn ListBox in C#

Normally a ListBox displays a textual representation of its objects but you can change that behavior to make it display anything you can draw. This example displays some multiline text entries.

The form's Load event handler uses the following code to make its ListBox owner-drawn and to create some multiline text items.
// Make the ListBox owner drawn.
private void Form1_Load(object sender, EventArgs e)
{
lstChoices.DrawMode = DrawMode.OwnerDrawVariable;

// Create some items.
lstChoices.Items.Add("Name: Mercury\nMass: 0.055 Earths\nYear: 87.9691 Earth days\nTemp: ?183 °C to 427 °C");
lstChoices.Items.Add("Name: Venus\nMass: 0.815 Earths\nYear: 243 Earth days");
lstChoices.Items.Add("Name: Earth\nMass: 1.0 Earths\nYear: 365.256 Earth days");
lstChoices.Items.Add("Name: Mars\nMass: 0.107 Earths\nYear: 686.971 Earth days");
}

When you make a ListBox owner-drawn, you must provide it with two event handlers: MeasureItem to determine how big the items should be and DrawItem to draw the items. The following code shows the example's MeasureItem event handler.

// Calculate the size of an item.
private int ItemMargin = 5;
private void lstChoices_MeasureItem(object sender, MeasureItemEventArgs e)
{
// Get the ListBox and the item.
ListBox lst = sender as ListBox;
string txt = (string)lst.Items[e.Index];

// Measure the string.
SizeF txt_size = e.Graphics.MeasureString(txt, this.Font);

// Set the required size.
e.ItemHeight = (int)txt_size.Height + 2 * ItemMargin;
e.ItemWidth = (int)txt_size.Width;
}

This code gets the ListBox from the event handler's sender parameter. It then gets the ListBox item that it should draw.

Next the code uses MeasureString to see how big the text will be when drawn. It adds twice a margin to the height and returns the resulting size through the e.ItemHeight and e.ItemWidth parameters.

The following code shows the program's DrawItem event handler.

// Draw the item.
private void lstChoices_DrawItem(object sender, DrawItemEventArgs e)
{
// Get the ListBox and the item.
ListBox lst = sender as ListBox;
string txt = (string)lst.Items[e.Index];

// Draw the background.
e.DrawBackground();

// See if the item is selected.
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
{
// Selected. Draw with the system highlight color.
e.Graphics.DrawString(txt, this.Font,
SystemBrushes.HighlightText, e.Bounds.Left, e.Bounds.Top + ItemMargin);
}
else
{
// Not selected. Draw with ListBox's foreground color.
using (SolidBrush br = new SolidBrush(e.ForeColor))
{
e.Graphics.DrawString(txt, this.Font, br,
e.Bounds.Left, e.Bounds.Top + ItemMargin);
}
}

// Draw the focus rectangle if appropriate.
e.DrawFocusRectangle();
}

The code gets the ListBox and the item to draw as before. It then calls e.DrawBackground to draw an appropriate background for the item depending on whether the item is currently selected.

The code then checks the e.State parameter to see if the Selected flag is set. If the flag is set, the program draws the item's text using the system's HighlightText brush. If the flag is not set, the program creates a brush using the ListBox's foreground color and draws the item with it.

After it has drawn the item, the program calls e.DrawFocusRectangle to draw a focus rectangle around the item if appropriate.

  

 

What did you think of this article?




Trackbacks
  • No trackbacks exist for this post.
Comments
  • No comments exist for this post.
Leave a comment

Submitted comments are subject to moderation before being displayed.

 Name

 Email (will not be published)

 Website

Your comment is 0 characters limited to 3000 characters.