Erik Porter (gravatar)

WindowsForms ComboBox Auto DropDownList Width

On a project I'm working on, I use some ComboBoxes that act as a breadcrumb control for a Wizard that I wrote, so the user can jump throughout the wizard to different steps easily and understand where they are.  Unfortunately, the ComboBoxes are dynamically filled from an admin section and can be anywhere from a few characters to a few hundred characters.  This would make the ComboBoxes very wide.  Unfortunately, the ComboBox doesn't automatically change the DropDownWidth Property based off of the items in the ComboBox.  I went ahead and wrote a Method to do that (This could be added into an inherited ComboBox to be used over and over too if you wanted) and thought I'd share:

VB

Private Sub FindWidthForDropDown(ByVal ComboBox As ComboBox)
    
Dim g As Graphics = ComboBox.CreateGraphics()
    
Dim IsDatabound As Boolean = Not ComboBox.DataSource Is Nothing AndAlso ComboBox.DisplayMember <> ""
    
Dim WidestWidth As Integer = ComboBox.DropDownWidth
    
Dim ValueToMeasure As String
    
Dim CurrentWidth As Integer

     For i As Integer = 0 To ComboBox.Items.Count - 1
         
If IsDatabound Then
              
ValueToMeasure = DirectCast(DirectCast(ComboBox.Items(i), DataRowView)(ComboBox.DisplayMember), String)
          Else
              
ValueToMeasure = DirectCast(ComboBox.Items(i), String)
         
End If

          CurrentWidth = CType(g.MeasureString(ValueToMeasure, ComboBox.Font).Width, Integer)
         
If CurrentWidth > WidestWidth Then WidestWidth = CurrentWidth
    
Next

     ComboBox.DropDownWidth = WidestWidth

     g.Dispose()
End Sub

C#

private void findWidthForDropDown(ComboBox comboBox)
{
    
bool isDatabound = comboBox.DataSource != null && comboBox.DisplayMember != null && comboBox.DisplayMember != "";
     int widestWidth = comboBox.DropDownWidth;
    
string valueToMeasure;
    
int currentWidth;

     using (Graphics g = comboBox.CreateGraphics())
     {
         
for
(int
i = 0; i < comboBox.Items.Count; i++)
         
{
              
if (isDatabound)
                   
valueToMeasure = (
string)((DataRowView)comboBox.Items[i])[comboBox.DisplayMember];
              
else
                   
valueToMeasure = (string)ComboBox.Items[i];

               currentWidth = (int)g.MeasureString(valueToMeasure, comboBox.Font).Width;
              
if (currentWidth > widestWidth) {widestWidth = currentWidth;}
          }
     }

     comboBox.DropDownWidth = widestWidth;
}

Simple, but hopefully helpful.  Just pass in the ComboBox and watch it's DropDownWidth change.

UPDATE: Check out the comments for some additional things to add to this method suggested by commenter(s).

8 Comments

  • I also wrote a method for doing this recently for a custom UserControl I wrote. Here is the code my code just for comparison purposes (please excuse the formatting): if (!this.comboBox1.IsHandleCreated || !(this.comboBox1.DataSource is IList)) return; using (Graphics g = this.comboBox1.CreateGraphics()) { int maxLength = 0; IList list = this.comboBox1.DataSource as IList; int numItems = Math.Min(list.Count, this.comboBox1.MaxDropDownItems); // Find the longest string in the first MaxDropDownItems for(int i = 0; i &lt; numItems; i++) maxLength = Math.Max(maxLength, (int)g.MeasureString(this.comboBox1.GetItemText(list[i]), this.comboBox1.Font).Width); maxLength += 20; // Add a little buffer for the scroll bar // Make sure we are inbounds of the screen int left = this.PointToScreen(new Point(0, this.Left)).X; if (maxLength &gt; Screen.PrimaryScreen.WorkingArea.Width - left) maxLength = Screen.PrimaryScreen.WorkingArea.Width - left; this.comboBox1.DropDownWidth = Math.Max(maxLength, this.comboBox1.Width); } If you notice one thing I different is use combobox.GetItemText(..) which I think is better than typecasting it to a DataRowView. One other suggestion is you may want to call dispose on your graphics object or just wrap it with a using statement. Wes

  • Ok, I'm getting rusty...thanks for pointing out that I forgot the Dispose (I'm embarassed now). As for the DataRowView, you're definitely right and using GetItemText would be better. I just copied it from an app I was working on and should also put that I make no promises that this is a perfect little piece of code. ;) I see you also have some other stuff like checking to make sure it doesn't go off the screen, etc. Good stuff for sure. I'll just add in the dispose to my code and let everyone see your code too...thanks! :)

  • http&#58;&#47;&#47; (gravatar)

    http:// said
    February 28, 2007

    Nice Article. It solved my problem. Events in which this code should go are - DataSourceChanged,Layout.

  • Jayaram, this was just a sample and was written two and a half years ago. If you'd like it to "go" where you talk about, then you'll have to do it yourself. :)

  • http&#58;&#47;&#47; (gravatar)

    http:// said
    August 24, 2007

    This is excellent. It is very helpful for me.

  • http&#58;&#47;&#47; (gravatar)

    http:// said
    January 21, 2008

    but how to deal with the dropdown portion right edge out of the screen???

  • http&#58;&#47;&#47; (gravatar)

    http:// said
    February 13, 2008

    That saved me a lot of time. TY

  • http&#58;&#47;&#47; (gravatar)

    http:// said
    July 25, 2008

    Fantastic ! Thank you so much for sharing this code.

Your Information
Mrs. Gravatar (gravatar)

<-- It's a gravatar

your comment