且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

允许每个项目在 Winforms 组合框(或列表框)中使用多行

更新时间:2023-11-28 19:53:04

我能够在 15 分钟内完成以下操作,所以是的.主要思想是处理DrawItem事件.

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.)