views:

22

answers:

1

The title pretty much says it all. Can this be done with relative ease?

Thanks!

+1  A: 

I was able to do the following in 15 minutes, so yes. The main idea is to handle the DrawItem event.

Following is my take on the problem (you can see another example, drawing icons in the items here).

public partial class Form1 : Form  
{
    public Form1()
    {
        InitializeComponent();

        this.comboBox1.DrawMode = DrawMode.OwnerDrawVariable;            
        this.comboBox1.DrawItem += new DrawItemEventHandler(comboBox1_DrawItem);
        this.comboBox1.Items.Add("Some text that needs to be take up two lines...");
        this.comboBox1.ItemHeight = 30;
    }

    IEnumerable<string> WrapString(string str, Graphics g, Font font, 
                                   int allowedWidth)
    {            
        string[] arr = str.Split(' ');            
        StringBuilder current = new StringBuilder();
        foreach (string token in arr)
        {                
            // TODO: You'll have to fix this, might break in marginal cases
            int width = 
              (int)g.MeasureString(current.ToString() + " " + token, font).Width;
            if (width > allowedWidth)
            {
                yield return current.ToString();
                current.Clear();
            }

            current.Append(token + " ");

        }
        yield return current.ToString();
    }

    void comboBox1_DrawItem(object sender, DrawItemEventArgs e)
    {
        Brush backgroundBrush, forgroundBrush;

        if (e.State == (DrawItemState.Selected | 
                    DrawItemState.NoAccelerator | DrawItemState.NoFocusRect) ||
            e.State == DrawItemState.Selected) 
        {
            forgroundBrush = Brushes.Black;
            backgroundBrush = Brushes.White;
        }
        else
        {
            forgroundBrush = Brushes.White;
            backgroundBrush = Brushes.Black;
        }

        // some way to wrap the string (on a space)           
        string str = (string)comboBox1.Items[e.Index];


        Rectangle rc = 
           new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height);
        e.Graphics.FillRectangle(forgroundBrush, rc);

        int stringHeight = 
               (int)e.Graphics.MeasureString(str, comboBox1.Font).Height;
        int lineNo = 0;
        foreach (string line in 
                      WrapString(str, e.Graphics, comboBox1.Font, e.Bounds.Width))
        {
            e.Graphics.DrawString(line, comboBox1.Font, backgroundBrush, 
                                  new PointF(0, lineNo * stringHeight + 5));
            lineNo++;
        }            
    }             
}

Usage: Create a regular form and drop one combobox on it.

(Note that this is of course only a naïve proof of concept - there's obviously room for improvement. Also it's just assuming that there will only be two lines rather than one. But it shows that this is possible.)

EDIT: Noticed now that you tagged the question as vb.net (nothing about that in the question though). Hope you're able to figure this out.

steinar