views:

39

answers:

1

Hello! Recently I reproduced strange behaviour of this message at my Windows 7. May be it is a feature, and may be it is not depends on Windows 7, please correct me if it is right behaviour. In MSDN we see

An application sends a CB_SETCURSEL message to select a string in the list of a combo box. If necessary, the list scrolls the string into view. The text in the edit control of the combo box changes to reflect the new selection, and any previous selection in the list is removed.

Code snippet below describes hot to reproduce behaviour:

private void ReproduceBehaviour()
{
    ComboBox comboBox = new ComboBox();
    Controls.Add(comboBox);
    comboBox.DataSource = new List<string> { "A", "b", "B", "C" };
    comboBox.DropDown += new EventHandler((o, e) => { comboBox.SelectedIndex = 2; });
}

So, when we set SelectedIndex = 2 on dropdown, item "B" should be selected. But it is strange to me, that item "b" (with index = 1) becomes selected! We can send CB_SETCURCELL message directly, nothing changed:

[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, Int32 lParam);
private void ReproduceBehaviour()
{
    ComboBox comboBox = new ComboBox();
    Controls.Add(comboBox);
    comboBox.DataSource = new List<string> { "A", "b", "B", "C" };
    comboBox.DropDown += new EventHandler((o, e) => { SendMessage(comboBox.Handle, 0x14e, 2, 0); });
}

Is this feature (?! o_O) or what I am doing wrong? Thanks for replies.

UPD. As adviced, I tried to set selection to listbox manually on dropdown eventhandler. No effect :(

private void ReproduceBehaviour()
{

    ComboBox comboBox = new ComboBox();
    Controls.Add(comboBox);
    comboBox.DataSource = new List<string> { "A", "b", "B", "C" };
    comboBox.DropDown += new EventHandler((o, e) =>
    {
        SendMessage(comboBox.Handle, 0x14e, 2, 0); // CB_SETCURSEL
        ComboBoxInfo pcbi = new ComboBoxInfo();
        pcbi.cbSize = Marshal.SizeOf(pcbi);
        GetComboBoxInfo(comboBox.Handle, ref pcbi);
        IntPtr result = SendMessage(pcbi.hwndList, 0x0186, 2, 0); // LB_SETCURSEL
    });
}

I have to used LB_SETCURSEL because LB_SETSEL returned LB_ERR (LB_SELSET available only for multiselectional listboxes but in ComboBox singleselectional listbox is used). Method call

IntPtr result = SendMessage(pcbi.hwndList, 0x0186, 2, 0); // LB_SETCURSEL

returns value '2', so I assume that selection was sucessfully set. But when dropdown is fully opened it selects incorrect value as usual :( May be DropDown event is not a right place to do this? I'm confused.

+2  A: 

It doesn't work the way you think it does. By assigning the SelectedIndex property, you don't select the dropdown list item, you set the text in the text box portion of the combo box. The drop down list responds to that by selecting the list item that matches the text box text. Problem is: it does so in a case-insensitive way.

You can easily see this for yourself by setting the 2nd item to, say, "D". That fixes it. Or set the first item to "b", now the first item gets selected.

No, there's no easy fix for that. The hard one is to obtain the handle to the listbox control in the dropdown event with CB_GETCOMBOBOXINFO, then sending it the LB_SETSEL message. The pragmatic fix is to not make the list items differ only by case. Tends to confuse the user anyway.

Hans Passant
Setting listbox selection directly doesn't works in DropDown eventhandler. I've updated question text with new results.
albicelestial
You forgot to remove CB_SETCURSEL
Hans Passant
If I remove it there is no effect too...
albicelestial
Hmya, LB_SETSEL still causes the text box to be filled with the selection so the original chain of events still overrides the list box selection.
Hans Passant