c++winapicomboboxmfcccombobox

CComboBox not selecting CurSel when dropped down


I have an alphabetically sorted combobox in a dialog. This combo contains multiple strings, but some are duplicated with different cases. i.e. we have an 'On' and an 'ON', an 'Off' and an 'OFF'. This may seem redundant but there is a reason, although this is not important right now.

The duplicates obviously appear one after the other in the list, with the capitalized strings first. i.e.:

OFF

Off

ON

On

When the user selects the 'On' (lower case), the correct index is set as CurSel and the correct string is displayed. However, when I click on the arrow of the combobox to drop down the list, it does not highlight the CurSel, but the one previous to it, the capitalized string. See images below.

This is was is selected in the dropdown:

Selected item before dropdown

This is what is selected in the combobox when expanding the dropdown.

Selected item after dropdown

I have captured the ON_CBN_DROPDOWN message, and checked the cursel value and it is as I expected.

I have also already subclassed this combobox so that I can search for strings in this list in a case-sensitive way, as I know its not implemented normally, so it may be what is causing my issue.

But I don't understand why the string would be overriding the cursel value at this stage? Should the CurSel value not be the one used to select the relevant item?

Any ideas on how I can fix this would be greatly appreciated.

EDIT: I have tried to capture the CBN_DROPDOWN message by overwriting the OnWndMsg. When this message occurs, I get the currently selected item (which is the correct item) before dropping down the menu. I then drop the menu, and call SetCurSel to what I retrieved before.

BOOL CMyComboBox::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam,    LRESULT *pResult)
{
    if(message == CBN_DROPDOWN)
    {
        int nCurSel = GetCurSel();
        if(nCurSel != CB_ERR)
        {
            ShowDropDown();
            SetCurSel(nCurSel);
            return TRUE;
        }

    }
    return CComboBox::OnWndMsg(message, wParam, lParam, pResult);
}

This kind of works but when I kill focus, or click on the dropdown arrow again to hide the dropdown, the wrong item is displayed in the text box. Is this a valid method, or am I completely off base here? What message is sent when the drop down is collapsed?

EDIT 2: I have implemented the case-sensitive combobox from code project and it works great.


Solution

  • Further to my comment. I think you will find that the internal mechanics is using SelectString to set the index when it is a dropdown style.

    The side effect is that it may not pick the right entry for you from the list. Therefore, given the nature of the content in your combo, please try this:

    int iIndex = m_cbData.FindStringExact(-1, "On");
    m_cbData.SetCurSel(iIndex);
    

    Or

    int iIndex = m_cbData.FindStringExact(-1, "OFF");
    m_cbData.SetCurSel(iIndex);
    

    However, be warned, the document for FindStringExact says the search is not case sensitive. But SelectString (default behaviour) is even worse.

    An alternative, which may resolve all of this, is to use SetWindowText and do it that way. This way, it does not matter what is in the listbox component. Eg:

    m_cbData.SetWindowText("On");
    m_cbData.SetWindowText("ON");
    

    And get the value for the variable by either mapping to a string, or directly using GetWindowText.

    UPDATE: Someone has done the work already! Here is a Case Sensitive ComboBox class:

    http://www.codeproject.com/Articles/1363/Case-sensitive-ComboBox