17
votes

I have a small problem that has been annoying me for some hours.

In my WinForms (.NET 3.5) application I create some ComboBoxes (DropDownStyle = DropDown) in a TableLayoutPanel at runtime and fill it with strings. The ComboBoxes are configured to resize automatically (Anchor = Left | Right).

The problem is that whenever the ComboBoxes are resized (i.e. the dialog is resized), the editbox portion of the ComboBox gets selected/highlighted entirely. In my opinion this creates a very confusing effect for the customer which I want to avoid.

The problem doesn't appear if the ComboBox has a fixed size.

Also note that changing the DropDownStyle is not an option - I need the possibility to enter text manually.

I already tried messing around with overriding the OnPaint method, which didn't quite work. I also tried clearing the selection in the ComboBox.Resize event, which worked in a way, but seemed like a very ugly solution - there was a lot of flicker, intentionally selected text became deselected and I would have to add the event handler to each and every ComboBox on my dialog.

Is there a better solution to this problem?

Thank you in advance.

Regards, Andy

8
The text portion isn't editable when you use DropDownList. Did you mean DropDown?Joe White

8 Answers

15
votes

This is an old question, but I found it searching for an answer and ended up implementing my own solution. Might as well post it here, right?

    foreach (var cb in Controls.OfType<ComboBox>())
    {
        cb.Resize += (sender, e) => {
            if (!cb.Focused)
                cb.SelectionLength = 0;
        };
    }

intentionally selected text became deselected

This WinForms bug doesn't affect selected ComboBoxes, so by ignoring the ones with Focus, we take care of the problem of losing current selections.

I would have to add the event handler to each and every ComboBox on my dialog.

Taken care of by the foreach loop. Put it in InitializeComponent() or your .ctor if you don't want to break the designer, or have the designer break this.

there was a lot of flicker

I'm only seeing flicker if I resize very fast, but I'm on Win7 so it might be different on XP.

3
votes

This appears to be a bug in the native Windows implementation of ComboBox with DropDownStyle of DropDown.

The fix detailed in the other answers here (setting the SelectionLength property to 0 (zero) in the ComboBox's Resize event) works well most of the time.

However, I found that even that fix to work around this bug does not always work. If the ComboBox is in a TableLayoutPanel, and if that TableLayoutPanel has more than one column with a Percent Size Type, then that fix often does not work.

A picture is worth a thousand words. See the following screen shot of a form I made to demonstrate the problem.

enter image description here

2
votes

Wow. Thank you guys!

Apparently this bug has persisted many years. I'm building a UserControl with .Net 4 (Visual Studio 2010). Here's is my slightlty modified version of bsneeze's code.

Cheers

using System.Windows.Forms;
using System.Linq;

public MyUserControlCtor()
{
    InitializeComponent();

    foreach( Control ctrl in Controls)
    {
        ComboBox cb = ctrl as ComboBox;
        if (cb != null)
        {
            cb.Resize += (sender, e) =>
            {
                if (!cb.Focused)
                    this.FCHZ_ComboBox.SelectionLength = 0;
            };
        }
    } 
}
2
votes

None of the answers so far worked for me. The only reliable method I have found was to post a message asynchronously via BeginInvoke that sets SelectionLength back to zero after all other activity on the control has completed. The amount of flicker is very annoying and unprofessional, but it is the best I could come up with...so far.

internal class FixedComboBox : ComboBox
{
    protected override void OnResize(EventArgs e)
    {
        if (IsHandleCreated && !Focused)
        {
            BeginInvoke((Action)(() =>
                {
                    SelectionLength = 0;
                }));
        }
        base.OnResize(e);
    }
}
2
votes

Worked for me to change the selectionLength to 0 when the WM_WINDOWPOSCHANGED gets called. Works even with the tableLayoutPanel set to %.

protected override void WndProc(ref Message m) {
    base.WndProc(ref m);

    if(m.Msg == 0x0047) {   // WM_WINDOWPOSCHANGED = 0x0047 
        if (SelectionLength != 0) {
            SelectionLength = 0;
        }
    }
}

0
votes

I found setting the selection length to 0 for the combo-box on the resize event of whatever control the combo-box is on causes a lot less flickering instead of doing it on the resize of the combo itself.

I actually achieved this in VB.Net but it should apply the same to C#.

0
votes

Handle the Resize event for the ComboBox's parent container. Put this line in there:

MyComboBox.SelectionLength = 0

An Example (VB, obviously):

Private Sub MyControl_Resize(sender As Object, e As EventArgs) Handles Me.Resize

    MyComboBox.SelectionLength = 0

End Sub

Good Luck to you!

--BP

0
votes

For a ComboBox inside a TableLayoutPanel setting the .SelectionLength = 0 on the ComboBox.Resize event does not work, but doing this on the TableLayoutPanel.Resize event does:

Private Sub TableLayoutPanel_Resize(sender As Object, e As EventArgs)
    Dim curr_panel = TryCast(sender, System.Windows.Forms.TableLayoutPanel)
    For Each curr_combo As ComboBox In curr_panel.Controls.OfType(Of ComboBox)
        If ((Not curr_combo.Focused) And curr_combo.DropDownStyle = ComboBoxStyle.DropDown) Then
                curr_combo.SelectionLength = 0
        End If
    Next
End Sub


dim panel as new TableLayoutPanel with {
    ...
}
AddHandler panel.Resize, AddressOf TableLayoutPanel_Resize