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

An editable multi-line listbox for .NET

Rate me:
Please Sign up or sign in to vote.
4.85/5 (42 votes)
4 Aug 2002Ms-PL3 min read 410.6K   7.8K   79   63
An owner drawn listbox that supports multi-line word-wrapped text as well as in-place editing.

Overview

MultiLineListBox is a fully owner drawn ListBox derived class that supports multi-line items as well as in-place editing of items. It has been wrapped into a class library for ease of deployment. You don't have to do anything special when using it. Just use it as you would use a normal list box. Whenever you add a string that's too long for a single line, the MultiLineListBox will wrap the long string into multiple lines. Editing items is also easy. Just right click on any item or press the F2 key when an item is selected, this will superimpose an edit box exactly on top of the selected or clicked item. You can make your changes and either press the Enter key or you can click anywhere else within the list box for the modifications to take effect. If you want to cancel the changes and get back to the original text, simply hit the Escape key.

The class will not allow you to make an item null, and will pop up a message box alert and won't let you take focus away from the item till you've either cancelled the modification by pressing Escape or you have entered some text.

If you enter a lot of text into the item edit text box, the overlaid text box itself will allow you to scroll vertically.

Using the class

Simply add the control to your toolbox. Now use it just as you  would be using a regular list box. Try entering long strings. And run the program. Try editing the strings by either pressing the F2 key or by right clicking on an item. See how the alert message box pops up when you try to modify an item string to a null string. I added this feature because in the project where I'll be using this, null strings are strictly forbidden. Perhaps you might want to allow null strings, if so feel free to comment out the relevant code in the source code.

Technical details

Well obviously the DrawMode is set to DrawMode.OwnerDrawVariable. We need to figure out the height required per item. This is how we do it it in the OnMeasureItem override,

C#
//...

string s = Items[e.Index].ToString();
SizeF sf = e.Graphics.MeasureString(s,Font,Width);
int htex = (e.Index==0) ? 15 : 10;
e.ItemHeight = (int)sf.Height + htex;			
e.ItemWidth = Width;

//...

Now we need to actually draw the  text as this is an owner drawn list box. We override OnDrawItem as shown below.

C#
protected override void OnDrawItem(DrawItemEventArgs e)
{
    //...

    /*chk if list box has any items*/
    if(e.Index > -1)
    {
        string s = Items[e.Index].ToString();                           

        /*Normal items*/
        if((e.State & DrawItemState.Focus)==0)
        {
            e.Graphics.FillRectangle(
                new SolidBrush(SystemColors.Window),
                e.Bounds);
            e.Graphics.DrawString(s,Font,
                new SolidBrush(SystemColors.WindowText),
                e.Bounds);              
            e.Graphics.DrawRectangle(
                new Pen(SystemColors.Highlight),e.Bounds);              
        }
        else /*Selected item, needs highlighting*/
        {
            e.Graphics.FillRectangle(
                new SolidBrush(SystemColors.Highlight),
                e.Bounds);
            e.Graphics.DrawString(s,Font,
                new SolidBrush(SystemColors.HighlightText),
                e.Bounds);
        }
    }
}

Well, so far so good. Now for the in-place editing, what we do is to derive a class from TextBox and add it to our list box. And we handle the OnMouseUp method to check if the user has right clicked an item.

C#
protected override void OnMouseUp(
    System.Windows.Forms.MouseEventArgs e)
{
    //...


        /* Is it a right mouse clk? */
        if(e.Button == MouseButtons.Right)
        {

            string s = Items[index].ToString();
            Rectangle rect = GetItemRectangle(index);

            //overlay the text box right over
            //the list box item to be edited
            tbox.Location = new Point(rect.X,rect.Y);
            tbox.Size = new Size(rect.Width,rect.Height);
            tbox.Text = s;              
            tbox.index = index;
            tbox.SelectAll();
            tbox.Show();
            tbox.Focus();
        }

    //...
}

And similarly we handle OnKeyDown for checking whether the user has pressed the F2 key.

C#
protected override void OnKeyDown(KeyEventArgs e)
{
    if(e.KeyData == Keys.F2)
    {
        //...

            string s = Items[index].ToString();
            Rectangle rect = GetItemRectangle(index);

            tbox.Location = new Point(rect.X,rect.Y);
            tbox.Size = new Size(rect.Width,rect.Height);               
            
        //...
    }
    
    //...
}

In the TextBox derived class we override both OnLostFocus and OnKeyPress (check for Enter key) and make checks to ensure that the user will not enter a null string. The source code can be examined for the finer details, but basically that's all the class does and this class is a private inner class of the MultiLineListBox class. I also check for the Escape key in the OnKeyPress handler to allow the user to cancel a modification.

Conclusion

I hope to get your feedback - both good and bad. I'd also like to know whether anyone actually found this useful enough to use in an application. Or whether the class can be improved in any particular manner. As for myself I spent the whole day dealing with various kinds of issues I ran into, mostly due to my custom control coding inexperience rather than due to any great difficulty in what I was attempting.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
United States United States
Nish Nishant is a technology enthusiast from Columbus, Ohio. He has over 20 years of software industry experience in various roles including Chief Technology Officer, Senior Solution Architect, Lead Software Architect, Principal Software Engineer, and Engineering/Architecture Team Leader. Nish is a 14-time recipient of the Microsoft Visual C++ MVP Award.

Nish authored C++/CLI in Action for Manning Publications in 2005, and co-authored Extending MFC Applications with the .NET Framework for Addison Wesley in 2003. In addition, he has over 140 published technology articles on CodeProject.com and another 250+ blog articles on his WordPress blog. Nish is experienced in technology leadership, solution architecture, software architecture, cloud development (AWS and Azure), REST services, software engineering best practices, CI/CD, mentoring, and directing all stages of software development.

Nish's Technology Blog : voidnish.wordpress.com

Comments and Discussions

 
GeneralMy vote of 5 Pin
Huỳnh Hữu Ân10-Mar-24 22:16
Huỳnh Hữu Ân10-Mar-24 22:16 
GeneralRe: My vote of 5 Pin
OriginalGriff10-Mar-24 22:20
mveOriginalGriff10-Mar-24 22:20 
GeneralRe: My vote of 5 Pin
Nish Nishant11-Mar-24 10:26
sitebuilderNish Nishant11-Mar-24 10:26 
GeneralRe: My vote of 5 Pin
OriginalGriff11-Mar-24 20:30
mveOriginalGriff11-Mar-24 20:30 
QuestionCatch empty string input and suppress error message Pin
BlackAsthesky25-Jul-19 11:47
BlackAsthesky25-Jul-19 11:47 
Hi there,

I have not tried that control yet, but I need to be able to suppress the error message on empty string input (when an item is is being edited) and then delete the item from the list box instead of throwing any kind of message or exception. This is essential for my use case. (How) can I achieve that?

Greetings

BlackAsthesky
QuestionBold Text Pin
Colin Anderson30-Dec-14 5:06
Colin Anderson30-Dec-14 5:06 
QuestionIs it possible to highlight words in the list item ? Pin
deep-it27-Aug-12 20:16
deep-it27-Aug-12 20:16 
QuestionHow to add an item dynamically to this editable list box? Pin
Harish Reddy K23-Jul-12 19:31
Harish Reddy K23-Jul-12 19:31 
GeneralMy vote of 5 Pin
David the Coder11-Dec-10 14:16
David the Coder11-Dec-10 14:16 
GeneralProblem when String is too long Pin
User 580643123-Sep-10 9:00
User 580643123-Sep-10 9:00 
GeneralCode Not Present Pin
dasprdav31-Aug-10 9:02
dasprdav31-Aug-10 9:02 
GeneralRe: Code Not Present Pin
Nish Nishant31-Aug-10 9:05
sitebuilderNish Nishant31-Aug-10 9:05 
Generalthx for the post and I have one question if you still have time for such projects ;) Pin
TKluza11-Jan-10 7:29
TKluza11-Jan-10 7:29 
GeneralNish Pin
Willie Hall24-Jun-09 9:52
Willie Hall24-Jun-09 9:52 
GeneralAdded support for "SetSelected" [modified] Pin
Member 425856019-Jan-09 11:15
Member 425856019-Jan-09 11:15 
GeneraldataSource Pin
bfis10813729-Jul-08 7:03
bfis10813729-Jul-08 7:03 
GeneralShweet!!!! Pin
shahbaznihal11-Jul-08 8:07
shahbaznihal11-Jul-08 8:07 
GeneralNice work! but one problem when editing Pin
sean 911-Jun-08 9:00
sean 911-Jun-08 9:00 
GeneralGet Text Pin
g8kpr007-Dec-06 14:42
g8kpr007-Dec-06 14:42 
GeneralThis is nice Pin
Krenshau755-Nov-06 17:16
Krenshau755-Nov-06 17:16 
GeneralSlight Update to allow for Multi-Select Pin
Moxie13-Oct-06 8:09
Moxie13-Oct-06 8:09 
GeneralRe: Slight Update to allow for Multi-Select Pin
Moxie13-Oct-06 8:11
Moxie13-Oct-06 8:11 
GeneralCool Pin
Paul Conrad8-Jul-06 7:22
professionalPaul Conrad8-Jul-06 7:22 
GeneralGreat Job DUDE [modified] Pin
Prashanth Kota11-Jun-06 11:49
Prashanth Kota11-Jun-06 11:49 
QuestionProblem Adding a User defined Index ID to the Listbox Pin
kkungli26-May-06 14:22
kkungli26-May-06 14:22 

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.