Home > Blockchain >  ComboBox auto DropDownWidth regardless of DataSource type
ComboBox auto DropDownWidth regardless of DataSource type

Time:09-28

I would like to resize any ComboBox dropdown width based on the longest string in the dropdown items. I want this to work on any ComboBox with items which means one whose items are strings, some object with DisplayMember set, or a DataTable. I found some code which works for strings, but not when a DisplayMember is set

static void resizeCombo(ComboBox cb)
{
    cb.DropDownWidth = cb.Items.Cast<string>().Max(x => TextRenderer.MeasureText(x, cb.Font).Width);
}

In the following three examples, the first which is just strings will work, but the following two don't work (cb.Items.Cast<string>() cast to string fails), and demonstrate that the DisplayMember can vary when bound to sources of different classes, so I can't just use "Name" for example

var c = new string[] { "Name1", "Name2" };
comboBox.DataSource = c.ToList();
resizeCombo(comboBox);

var c1 = new Class1[] { new Class1() { ID = 1, Name1 = "Name1" }, new Class1() { ID = 2, Name1 = "Name2" } };
comboBox1.DisplayMember = "Name1";
comboBox1.ValueMember = "ID";
comboBox1.DataSource = c1.ToList();
resizeCombo(comboBox1);

var c2 = new Class2[] { new Class2() { ID = 2, Name2 = "Name1" }, new Class2() { ID = 2, Name2 = "Name2" } };
comboBox2.DisplayMember = "Name2";
comboBox2.ValueMember = "ID";
comboBox2.DataSource = c2.ToList();
resizeCombo(comboBox2);

I could reflect the DisplayMember, and find the strings by name, and it may solve the List<class> case, but not DataTable.

I am looking for a method to get all the strings in the ComboBox regardless of how they are added. Is there one?

CodePudding user response:

Combobox has GetItemText method that returns the string representation of item.

This should work:

    static void resizeCombo(ComboBox cb)
    {
        if (cb.Items.Count == 0) cb.DropDownWidth = cb.Width;
        else
        {
            int maxWidth = int.MinValue;
            for (int i = 0; i < cb.Items.Count; i  )
            {
                maxWidth = Math.Max(maxWidth, TextRenderer.MeasureText(cb.GetItemText(cb.Items[i]), cb.Font).Width);
            }
            if (cb.Items.Count > cb.MaxDropDownItems) maxWidth  = SystemInformation.VerticalScrollBarWidth                    
            cb.DropDownWidth = maxWidth;
        }
    }

To test with DataTable:

        DataTable t = new DataTable();
        t.Columns.Add(new DataColumn("ID", typeof(int)));
        t.Columns.Add(new DataColumn("Name2", typeof(string)));

        t.Rows.Add(new object[] { 1, "Somename" });
        t.Rows.Add(new object[] { 2, "Some other name" });

        comboBox2.DisplayMember = "Name2";
        comboBox2.ValueMember = "ID";
        comboBox2.DataSource = t;
        resizeCombo(comboBox2);

NB! For this to work, do not use the resize function in a form's constructor. Use it from the Load event or similar, once the form is already up and running.

  • Related