Click here to Skip to main content
15,881,588 members
Articles / Programming Languages / C#
Article

An auto-resize C# ListBox

Rate me:
Please Sign up or sign in to vote.
3.67/5 (9 votes)
16 Jul 20022 min read 233.4K   3.8K   41   25
A custom ListBox that can resize its items automatically
Before resize After resize After another resize

What's the problem?

I had to write a little tool that validates an input file according to a file format specification. To add some visual candy to the application, I wanted to include a little status window where all relevant parsing messages (errors, warnings and so on) with some descriptive text are shown.

So the first try was to inherit from the standard ListBox class and implement custom drawing code with a little icon, a headline and the message text. To support varying text sizes I subscribed to the MeasureItem event and calculated the item heights individually for each item. This worked fine until I resized my control the first time: No more MeasureItem events!

A quick look into the documentation revealed the sentence: "Occurs when an owner-drawn ListBox is created". As I added my parsing messages to the listbox on the fly, a continuous re-creation of the control was not an option (besides being inefficient). So this was a dead end.

The solution

After playing around with some possible workarounds without success, I came to the conclusion that this would require a more fundamental approach: I had to write an own listbox that would behave like I had expected it from the standard listbox right from the beginning. The task turned out to be easier that I first expected.

The solution consists basically of two classes: ResizableListBox and MessageListBox. The former is the replacement for the standard ListBox class. It tries to mimic the real ListBox as closely as possible regarding events, properties and methods. Although I have to admit that it's not 100% complete (data binding is missing) but it should do the trick in most cases. It does not provide any additional benefit over the original listbox when used alone. The only difference is, that it fires the MeasureItem event every time the control is redrawn. The latter implements the actual custom listbox with the fancy drawing.

How to use it

First add the ResizableListBox to your project. Then create a derived class and subscribe to the MeasureItem event:

C#
public class MessageListBox : ResizableListBox 
{
    public MessageListBox()
    {    
        InitializeComponent();                    
        this.MeasureItem += new MeasureItemEventHandler(
	    this.MeasureItemHandler);
        
        //more ctor code here
        ...
    }
        
    ...
}

Add a event handler and set the MeasureItemEventArgs.ItemHeight property:

C#
private void MeasureItemHandler(
    object sender, MeasureItemEventArgs e)
{

    int MainTextHeight;            
    ParseMessageEventArgs item;
    item =  (ParseMessageEventArgs) Items[e.Index];
    int LinesFilled, CharsFitted;
            
    // as we do not use the same algorithm to calculate 
    // the size of the text (for performance reasons)
    // we need to add some safety margin ( the 0.9 factor ) 
    // to ensure that always all text is displayed
    int width = (int)((this.Width - m_MainTextOffset) * 0.9);
    int height = 200;
    Size sz = new Size(width , height);    

    e.Graphics.MeasureString(item.MessageText, this.Font, sz,
        StringFormat.GenericDefault, out CharsFitted, 
        out LinesFilled);
            
    MainTextHeight = LinesFilled * this.Font.Height;

    e.ItemHeight = IconList.ImageSize.Height + MainTextHeight + 4;
}

To implement your own drawing code also makes sense:

C#
protected override void OnDrawItem( DrawItemEventArgs e)
{
    //custom drawing goes here
    ...
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Germany Germany
If you are not living on the edge you are wasting space Wink | ;)

Comments and Discussions

 
QuestionLicense missing Pin
stef89914-Apr-21 21:49
stef89914-Apr-21 21:49 
Generaladding to the list next line Pin
jinfrics28-Jun-09 19:22
jinfrics28-Jun-09 19:22 
GeneralRe: adding to the list next line Pin
yuzaihuan8-May-14 3:30
yuzaihuan8-May-14 3:30 
GeneralTriggering ListBox.Measureitem Pin
The_Mega_ZZTer22-Aug-05 10:18
The_Mega_ZZTer22-Aug-05 10:18 
GeneralRe: Triggering ListBox.Measureitem Pin
Claudio Nicora5-Nov-08 22:42
Claudio Nicora5-Nov-08 22:42 
GeneralMouse Wheel problem Pin
adi8816-Aug-04 22:02
adi8816-Aug-04 22:02 
GeneralAlso, some few advices... Pin
adi8816-Aug-04 22:26
adi8816-Aug-04 22:26 
GeneralRe: Also, some few advices... Pin
Christian Tratz6-Aug-04 23:27
Christian Tratz6-Aug-04 23:27 
GeneralRe: Also, some few advices... Pin
Lelieveld25-Aug-04 1:32
Lelieveld25-Aug-04 1:32 
GeneralRe: Mouse Wheel problem Pin
linlinzongzong217-Apr-05 4:29
linlinzongzong217-Apr-05 4:29 
GeneralSome adjustments Pin
Lelieveld16-Jun-04 23:08
Lelieveld16-Jun-04 23:08 
GeneralEasier way to do this Pin
Johan Danforth13-Jan-04 22:04
Johan Danforth13-Jan-04 22:04 
GeneralThis code Even not Compiling in VS 2003 Pin
Irakli Lomidze9-Jan-04 4:03
Irakli Lomidze9-Jan-04 4:03 
GeneralRe: This code Even not Compiling in VS 2003 Pin
Christian Tratz11-Jan-04 6:21
Christian Tratz11-Jan-04 6:21 
GeneralRe: This code Even not Compiling in VS 2003 Pin
Lelieveld16-Jun-04 22:57
Lelieveld16-Jun-04 22:57 
GeneralFixed a bug computing AutoScrollMinSize Pin
Iluminar Magician6-Oct-02 20:05
Iluminar Magician6-Oct-02 20:05 
GeneralRe: Fixed a bug computing AutoScrollMinSize Pin
junkmegently20-Nov-02 12:56
junkmegently20-Nov-02 12:56 
GeneralRe: Fixed a bug computing AutoScrollMinSize Pin
Matt Whitfield7-Sep-08 12:00
Matt Whitfield7-Sep-08 12:00 
Questionsome unneeded work? Pin
Andy Smith16-Jul-02 7:50
Andy Smith16-Jul-02 7:50 
If you wanted ListBox to call MeasureItem each time it called draw item...
doesn't setting the DrawMode property to DrawMode.OwnerDrawVariable accomplish that?
AnswerA possible explanation Pin
Shog916-Jul-02 13:32
sitebuilderShog916-Jul-02 13:32 
AnswerRe: some unneeded work? Pin
Christian Tratz16-Jul-02 20:59
Christian Tratz16-Jul-02 20:59 
GeneralRe: some unneeded work? Pin
Andy Smith17-Jul-02 5:34
Andy Smith17-Jul-02 5:34 
GeneralRe: some unneeded work? Pin
Christian Tratz17-Jul-02 8:01
Christian Tratz17-Jul-02 8:01 
GeneralGreat. Only problem it will crash when resize to minimum width Pin
shilin16-Jul-02 7:29
shilin16-Jul-02 7:29 
GeneralFixed Pin
Christian Tratz16-Jul-02 23:45
Christian Tratz16-Jul-02 23:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.