ComboBox内容的自动宽度调整

58
有人知道如何将ComboBox下拉的内容宽度设置为自适应大小吗?我指的不是ComboBox本身,而是打开的内容。
10个回答

86

你不能直接使用它。

进行小技巧

首先遍历下拉框的所有项,通过将文本赋值给标签来检查每个项的宽度。然后每次检查宽度时,如果当前项的宽度大于之前的项,则更改最大宽度。

int DropDownWidth(ComboBox myCombo)
{
    int maxWidth = 0;
    int temp = 0;
    Label label1 = new Label();

    foreach (var obj in myCombo.Items)
    {
        label1.Text = obj.ToString();
        temp = label1.PreferredWidth;
        if (temp > maxWidth)
        {
            maxWidth = temp;
        }
    }
    label1.Dispose();
    return maxWidth;           
}

private void Form1_Load(object sender, EventArgs e)
{
    comboBox1.DropDownWidth = DropDownWidth(comboBox1);
}

或者

stakx所建议的,你可以使用TextRenderer类。

int DropDownWidth(ComboBox myCombo)
{
    int maxWidth = 0, temp = 0;
    foreach (var obj in myCombo.Items)
    {
        temp = TextRenderer.MeasureText(obj.ToString(), myCombo.Font).Width;
        if (temp > maxWidth)
        {
            maxWidth = temp;
        }
    }
    return maxWidth;
}

9
相关的话题上,我想当使用label1.PreferredWidth的技巧表现良好时,一个稍微更直接和"表达性"更强的测量文本宽度的方法是使用TextRenderer.MeasureText...? - stakx - no longer contributing
3
"obj.ToString()" 不是绑定数据下拉框的正确文本。 - Sina Iravanian
13
我更喜欢这个LINQ查询语句: comboBox1.DropDownWidth = comboBox1.Items.Cast<string>().Max(x => TextRenderer.MeasureText(x, comboBox1.Font).Width);,它可以让下拉框的宽度适应其最长选项的长度。 - Andy
3
obj.ToString() 可能与组合框的 DisplayMember 属性不同。myCombo.GetItemText(obj) 明显比其他答案更正确。 - Russell Trahan
3
这是使用 GetItemText 的一行代码: comboBox1.DropDownWidth = comboBox1.Items.Cast<object>().Max(o => TextRenderer.MeasureText(comboBox1.GetItemText(o), comboBox1.Font).Width);注:这段代码会根据下拉框内的选项长度自动调整下拉框的宽度。 - Alain
显示剩余9条评论

22

obj.ToString() 对我无效,建议使用 myCombo.GetItemText(obj)。这对我有效:

private int DropDownWidth(ComboBox myCombo)
{
    int maxWidth = 0, temp = 0;
    foreach (var obj in myCombo.Items)
    {
        temp = TextRenderer.MeasureText(myCombo.GetItemText(obj), myCombo.Font).Width;
        if (temp > maxWidth)
        {
            maxWidth = temp;
        }
    }
    return maxWidth + SystemInformation.VerticalScrollBarWidth;
}

1
很好的发现。myCombo.GetItemText(obj)绝对比其他答案更正确。obj.ToString()可能与组合框的DisplayMember属性不同。 - Russell Trahan

19

这里有一个非常优雅的解决方案。只需将您的组合框订阅到此事件处理程序即可:

 private void AdjustWidthComboBox_DropDown(object sender, EventArgs e)
        {
            var senderComboBox = (ComboBox)sender;
            int width = senderComboBox.DropDownWidth;
            Graphics g = senderComboBox.CreateGraphics();
            Font font = senderComboBox.Font;

            int vertScrollBarWidth = (senderComboBox.Items.Count > senderComboBox.MaxDropDownItems)
                    ? SystemInformation.VerticalScrollBarWidth : 0;

            var itemsList = senderComboBox.Items.Cast<object>().Select(item => item.ToString());

            foreach (string s in itemsList)
            {
                int newWidth = (int)g.MeasureString(s, font).Width + vertScrollBarWidth;

                if (width < newWidth)
                {
                    width = newWidth;
                }
            }

            senderComboBox.DropDownWidth = width;
        }

这段代码来自codeproject:调整组合框下拉列表宽度以适应最长字符串宽度。 但我已经修改它可以与任何数据(不仅仅是字符串)填充的组合框一起使用。


+1 考虑垂直滚动条宽度并允许任何内容,而不仅仅是字符串。可惜没有像其他答案中使用 TextRenderer 类。 - MarkJ
6
使用完Graphics实例后,应该立即将其处理掉,最好的方法是将其包装在using块中以进行自动释放。 - vgru
我喜欢这个解决方案,但我想改变ComboBox的宽度,但在点击下拉菜单后看到宽度变化很奇怪。因为我是动态地将ComboBox添加到FlowLayoutPanel中的,所以我订阅了ParentChanged事件,现在看起来好多了。 - Deolus

2
请投票支持以下algreat的答案。
我只是修改了algreat的答案,使用代码调整了整个控件的大小。
我本来会在评论中添加此内容,但无法在评论中添加格式化代码。
private void combo_DropDown(object sender, EventArgs e)
{
    //http://www.codeproject.com/Articles/5801/Adjust-combo-box-drop-down-list-width-to-longest-s
    ComboBox senderComboBox = (ComboBox)sender;
    int width = senderComboBox.DropDownWidth;
    Graphics g = senderComboBox.CreateGraphics();
    Font font = senderComboBox.Font;
    int vertScrollBarWidth =
        (senderComboBox.Items.Count > senderComboBox.MaxDropDownItems)
        ? SystemInformation.VerticalScrollBarWidth : 0;

    int newWidth;
    foreach (string s in ((ComboBox)sender).Items)
    {
        newWidth = (int)g.MeasureString(s, font).Width
            + vertScrollBarWidth;
        if (width < newWidth)
        {
            width = newWidth;
        }

        if (senderComboBox.Width < newWidth)
        {
            senderComboBox.Width = newWidth+ SystemInformation.VerticalScrollBarWidth;
        }
    }
    senderComboBox.DropDownWidth = width;
}

2

这段代码与Javed Akram的第二个建议基本相同,只是加入了垂直滚动条的宽度:

int setWidth_comboBox(ComboBox cb)
{
  int maxWidth = 0, temp = 0;
  foreach (string s in cb.Items)
  {
    temp = TextRenderer.MeasureText(s, cb.Font).Width;
    if (temp > maxWidth)
    {
      maxWidth = temp;
    }
  }
  return maxWidth + SystemInformation.VerticalScrollBarWidth;
}

使用以下代码(在具有名称为myComboBox的组合框的表单上):

myComboBox.Width = setWidth_comboBox(myComboBox);

1

旧但经典,希望能够快速运作

private int GetDropDownWidth(ComboBox combo)
{
    object[] items = new object[combo.Items.Count];
    combo.Items.CopyTo(items, 0);
    return items.Select(obj => TextRenderer.MeasureText(combo.GetItemText(obj), combo.Font).Width).Max();
}

1
请看下面我的解决方案:

   private int AutoSizeDropDownWidth(ComboBox comboBox)
        {
            var width = cmboxUnit.DropDownWidth;
            var g = cmboxUnit.CreateGraphics();
            var font = cmboxUnit.Font;

            var verticalScrollBarWidth = cmboxUnit.Items.Count > cmboxUnit.MaxDropDownItems
                ? SystemInformation.VerticalScrollBarWidth : 0;

            var itemsList = cmboxUnit.Items.Cast<object>().Select(item => item);

            foreach (DataRowView dr in itemsList)
            {
                int newWidth = (int)g.MeasureString(dr["Name"].ToString(), font).Width + verticalScrollBarWidth;

                if (width < newWidth)
                {
                    width = newWidth;
                }
            }
            return width;
        }

1

此答案基于@user2361362的回答。代码使用LINQ进行修改,并转换为一个函数,该函数可设置给定ComboBox的下拉框宽度:

private void SetComboBoxDropDownWidth(ComboBox comboBox)
{
    var width = (from object obj in comboBox.Items
            select TextRenderer.MeasureText(comboBox.GetItemText(obj), comboBox.Font).Width)
        .Prepend(0)
        .Max();
    comboBox.DropDownWidth = width + SystemInformation.VerticalScrollBarWidth;
}

0

这是一个老问题,但我刚遇到它,并结合了几个答案来解决它。我喜欢被接受的答案的简单性,但希望有些东西可以与组合框中的任何对象类型一起使用。我还想通过扩展方法利用该方法。

    public static int AutoDropDownWidth(this ComboBox myCombo)
    {
        return AutoDropDownWidth<object>(myCombo, o => o.ToString());
    }
    public static int AutoDropDownWidth<T>(this ComboBox myCombo, Func<T, string> description)
    {
        int maxWidth = 1;
        int temp = 1;
        int vertScrollBarWidth = (myCombo.Items.Count > myCombo.MaxDropDownItems)
                ? SystemInformation.VerticalScrollBarWidth : 0;

        foreach (T obj in myCombo.Items)
        {
            if (obj is T)
            {
                T t = (T)obj;
                temp = TextRenderer.MeasureText(description(t), myCombo.Font).Width;
                if (temp > maxWidth)
                {
                    maxWidth = temp;
                }
            }

        }
        return maxWidth + vertScrollBarWidth;
    }

如果我的类是这样的:

public class Person
{
    public string FullName {get;set;}
}

我可以像这样自动调整组合框下拉宽度:
cbPeople.DropDownWidth = cbPeople.AutoDropDownWidth<Person>(p => p.FullName);

-2

TComboBox.ItemWidth是您要查找的属性。它具有您想要的行为,而无需任何编码。只需在设计时或以编程方式将其设置为比Width大的某些值,当用户下拉框时,他们将获得更宽的选择列表。


1
首先,问题要求进行自动调整大小,这正好与显式设置宽度相反。但是其次,您的意思甚至不清楚。什么是TComboBox?您所说的ItemWidth属性是什么?https://learn.microsoft.com/en-us/search/?scope=.NET&terms=combobox%20itemwidth 没有任何结果。 - Peter Duniho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接