58

Does anybody know a way to set the ComboBox's content's width to autosize

I do not mean the ComboBox itself, just the opened content.

Breeze
  • 2,010
  • 2
  • 32
  • 43
unicorn
  • 829
  • 2
  • 8
  • 13

10 Answers10

86

You can't use it directly.

Do a trick

First iterate through all items of your combobox, check for the width of every items by assigning the text to a label. Then, check width every time, if width of current item gets greater than previous items then change the maximum width.

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);
}

OR

As suggested by stakx, you can use TextRenderer class

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;
}
Andy
  • 3,997
  • 2
  • 19
  • 39
Javed Akram
  • 15,024
  • 26
  • 81
  • 118
  • 1
    +1, nice answer. Without having tried this out, I'm curious: Is `label1.PreferredWidth` already computed correctly right after setting `label1.Text`? (After all, the UI won't get a chance to update itself while this code is running. I realise that `label1` isn't actually added to any form, but nevertheless... I'm surprised that this should work.) – stakx - no longer contributing Jan 30 '11 at 11:15
  • @stakx, I tried with `label1.Width` but it was not working, since it was not added to UI. So, I used `label1.PreferredWidth`. :) – Javed Akram Jan 30 '11 at 11:18
  • 9
    On a related note, I guess that while this trick with `label1.PreferredWidth` might work just fine, a slightly more direct and "expressive" way of measuring text width would be to use [`TextRenderer.MeasureText`](http://msdn.microsoft.com/en-us/library/system.windows.forms.textrenderer.measuretext.aspx)...? – stakx - no longer contributing Jan 30 '11 at 11:19
  • i tried it on a combobox that didn't needed it, and it streched anyway, any ideas why? – unicorn Jan 30 '11 at 14:31
  • i tried setting the dropdownwidth directly to a specific value, and it ignore the value i put and making the width too big – unicorn Jan 30 '11 at 14:38
  • @unicorn: I have no idea. try `maxWidth = myCombo.Width;` inplace of `maxWidth = 0`. – Javed Akram Jan 30 '11 at 14:38
  • tried that, the combobox's width is 106, and I did combobox1.DropDownWidth=40, and it's ovverlapping. for some reason setting the dropdownwidth force it to ovverlap – unicorn Jan 30 '11 at 14:48
  • @unicorn: I think you are trying to make your Dropdown less than the width of Combobox. You can't make it less than combobox width. – Javed Akram Jan 30 '11 at 14:54
  • LINQ one liner: (from object item in comboBox.Items select TextRenderer.MeasureText(item.ToString(), comboBox.Font).Width).Max(); – mheyman May 21 '12 at 18:45
  • 3
    `obj.ToString()` is not a correct text for data-bound combo-boxes. – Sina Iravanian Jun 04 '13 at 05:38
  • 13
    I prefer the LINQ query: `comboBox1.DropDownWidth = comboBox1.Items.Cast().Max(x => TextRenderer.MeasureText(x, comboBox1.Font).Width);` – Andy Apr 24 '14 at 13:09
  • 1
    if anyone ins conserned with speed i tested them with 11 items and a stopwatch and got the label at 50ms and textrender at 42ms the label was inclosed in a using though. :) but cool example javed! –  Nov 27 '14 at 10:53
  • 3
    `obj.ToString()` can be different than the `DisplayMember` property of the combobox. `myCombo.GetItemText(obj)` is definitely more correct than the other answers – Russell Trahan Dec 03 '15 at 15:43
  • 3
    Here's a one-liner using `GetItemText`: `comboBox1.DropDownWidth = comboBox1.Items.Cast().Max(o => TextRenderer.MeasureText(comboBox1.GetItemText(o), comboBox1.Font).Width);` – Alain Jul 18 '18 at 12:54
22

obj.ToString() doesn't work for me, I suggest to use myCombo.GetItemText(obj). This works for me:

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;
}
user2361362
  • 221
  • 2
  • 2
  • 1
    Nice catch. `myCombo.GetItemText(obj)` is definitely more correct than the other answers. `obj.ToString()` can be different than the `DisplayMember` property of the combobox. – Russell Trahan Dec 03 '15 at 15:43
19

Here is very elegant solution. Just subscribe your combobox to this event handler:

 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;
        }

This code was taken from the codeproject: Adjust combo box drop down list width to longest string width. But I have modified it to work with comboboxes filled with any data (not only strings).

algreat
  • 8,592
  • 5
  • 41
  • 54
  • +1 for accounting for vertical scroll bar width and allowing any contents, not just strings. Pity not to use TextRenderer class as in the other answers though. – MarkJ May 16 '13 at 16:38
  • 6
    You should remember to dispose the `Graphics` instance right after use, best by wrapping it inside a `using` block. – vgru Dec 20 '13 at 12:37
  • I like this solution but I wanted to change the width of the ComboBox also and it looked wierd seeing the width change after clicking the drop-down. Because I was adding the ComboBox dynamically to a FlowLayoutPanel I instead subscribed to the ParentChanged event and it looks a lot better. – Deolus Mar 07 '19 at 14:37
2

Mostly the same code as in Javed Akram's second suggestion, but the width of the vertical scroll bar is added:

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;
}

Use the code like this (on a form with a combobox with the name myComboBox):

myComboBox.Width = setWidth_comboBox(myComboBox);
matsolof
  • 245
  • 2
  • 6
2

Vote for algreat's answer below.

I simply modified algreat's answer with code resize the entire control.

I would have just added it as a comment but couldn't add formatted code on the comment.

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;
}
SensorSmith
  • 1,129
  • 1
  • 12
  • 25
Gary Kindel
  • 17,071
  • 7
  • 49
  • 66
1

Old but classic, hope to work fast enough

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();
}
HDJEMAI
  • 9,436
  • 46
  • 67
  • 93
1

Please see my solution below:

   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;
        }
Ismail Saifo
  • 53
  • 1
  • 11
1

This answers is based on @user2361362 answer. The code is modified using LINQ and converted into a function that sets the drop down width of a given 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;
}
jrn6270
  • 61
  • 11
0

This is an old question, but I just ran into it and combined a couple of the answers for my solution. I liked the simplicity of the accepted answer but wanted something that would work with any object type in the combo box. I also wanted to make use of the method through an extension method.

    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;
    }

This way if my class is:

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

I could auto adjust the combo box drop down width like this:

cbPeople.DropDownWidth = cbPeople.AutoDropDownWidth<Person>(p => p.FullName);
Aaron Schooley
  • 467
  • 3
  • 4
-2

TComboBox.ItemWidth is the property you seek. It has the behavior you want without any coding. Just set it at design time or programmatically to something bigger than Width, and when the user pulls down the box they will get a wider list of choices.

phr
  • 1
  • 2
  • 1
    First of all, the question is asking for **autosize**, which is exactly the opposite of setting a width explicitly. But secondly, it's not even clear what you mean here. What is `TComboBox`? What `ItemWidth` property is it that you are talking about? https://learn.microsoft.com/en-us/search/?scope=.NET&terms=combobox%20itemwidth turns up nothing. – Peter Duniho Jun 04 '21 at 01:39