alex
alex

Reputation: 51

How to remove the text selection highlight from a ComboBox permanently?

I am interested in removing the text selection of ComboBoxes with DropDownStyle = DropDown.
When I add/remove or close the DropPown, then the Item is selected.
I am not able to clear the selected text. Do you have some idea how to do this?

This code does not work:

comboBox.SelectionLenght = 0;
comboBox.SelectionStart = comboBox.Text.Legnth;
comboBox.Select(0,0);

I can see that the text is highlighted after this line:

selectedComboBox.Items.Add(redCompetitorName);

Upvotes: 3

Views: 2071

Answers (2)

Jimi
Jimi

Reputation: 32248

You can defer the execution of the Select() method, calling BeginInvoke() in the SelectedIndexChanged event handler (or SelectionChangedCommitted, if you want this to happen only when a User selects an Item manually).

By deferring the execution (this action is enqueued in the message loop), the Select() action is performed only after the ComboBox.Text has been set and highlighted. So your command is not overridden by the default behavior.

private void comboBox_SelectedIndexChanged(object sender, EventArgs e)
{
    // Set the caret to the start of the ComboBox text
    BeginInvoke(new Action(()=> comboBox.Select(0, 0)));

    // OR - set the caret to the end of the text instead
    BeginInvoke(new Action(()=> comboBox.Select(int.MaxValue, 0)));
}

This concept applies in other contexts of course.
You can use this method in other situations, when you need to perform an action, in the UI, that is executed only after the current (or the current sequence of the already scheduled actions) has completed.

If you want a more involved solution that prevents all kind of selection highlights in a ComboBox, you can use a Custom Control derived from ComboBox, get the Handle of its Edit Control, use a NativeWindow to intercept its messages. Override WndProc to handle EM_SETSEL and call PostMessage to remove the selection (only when the starting position is > 0, otherwise you risk to get stuck in a weird auto-loop which has an effect that's usually referred to as StackOverflow :).

using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

[DesignerCategory("code")]
public class ComboBoxNoFocus : ComboBox
{
    IntPtr editHandle = IntPtr.Zero;
    private EditNativeWindow editControl = null;

    public ComboBoxNoFocus() { }

    protected override void OnHandleCreated(EventArgs e)
    {
        base.OnHandleCreated(e);
        editHandle = GetComboBoxEditInternal(this.Handle);
        editControl = new EditNativeWindow(editHandle);
    }


    public class EditNativeWindow : NativeWindow
    {
        private const int EM_SETSEL = 0x0B1;
        public EditNativeWindow() : this(IntPtr.Zero) { }
        public EditNativeWindow(IntPtr handle)
        {
            if (handle != IntPtr.Zero) {
                this.AssignHandle(handle);
            }
        }

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg) {
                case EM_SETSEL:
                    int pos = m.LParam.ToInt32();
                    if (pos > 0) {
                        PostMessage(this.Handle, EM_SETSEL, 0, 0);
                    }
                    return;
                default:
                    // Other operations
                    break;
            }
            base.WndProc(ref m);
        }
    }

    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    internal static extern bool GetComboBoxInfo(IntPtr hWnd, ref COMBOBOXINFO pcbi);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);

    [StructLayout(LayoutKind.Sequential)]
    internal struct COMBOBOXINFO
    {
        public int cbSize;
        public Rectangle rcItem;
        public Rectangle rcButton;
        public int buttonState;
        public IntPtr hwndCombo;
        public IntPtr hwndEdit;
        public IntPtr hwndList;
        public void Init() => this.cbSize = Marshal.SizeOf<COMBOBOXINFO>();
    }

    internal static IntPtr GetComboBoxEditInternal(IntPtr cboHandle)
    {
        var cbInfo = new COMBOBOXINFO();
        cbInfo.Init();
        GetComboBoxInfo(cboHandle, ref cbInfo);
        return cbInfo.hwndEdit;
    }
}

Upvotes: 5

Jonathan Applebaum
Jonathan Applebaum

Reputation: 5986

Set the focus to another control in your form after a new item is selected, using the SelectedIndexChanged event of the Combobox.

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    button1.Focus();
}

Upvotes: 2

Related Questions