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
Wes said
September 27, 2004
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 < 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 > 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
Erik Porter said
September 27, 2004
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:// said
February 28, 2007
Nice Article. It solved my problem. Events in which this code should go are - DataSourceChanged,Layout.
HumanCompiler said
February 28, 2007
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:// said
August 24, 2007
This is excellent. It is very helpful for me.
http:// said
January 21, 2008
but how to deal with the dropdown portion right edge out of the screen???
http:// said
February 13, 2008
That saved me a lot of time. TY
http:// said
July 25, 2008
Fantastic ! Thank you so much for sharing this code.