4
votes

I have a ComboBox that is part of a detail display related to a data grid containing rows from a database. No binding to the ComboBox exists, I am doing this manually. The ComboBox allows manual entry, as if it were a text field, while still providing a drop-down of choices.

My issue is that if I have manually entered text in the field, and the drop-down is clicked, the ComboBox apparently wants to seek out a match. Also, it appears that the search is simple, so KG matches KG/Day. I must avoid this and force an exact match.

But further, I think I need to be able to govern the entire process myself, because to further complicate the matter, the drop-down item would actually read KG/Day - kilograms/day. The database field from which the data is fetched, however, is only storing the portion prior to the hyphen, so KG/Day.

So, I need to intercept the drop-down action in a way that allows me to do two things:

1) Perform my own search to find whether or not I have ad-hoc text, or a "real" match. As in that it was originally selected from the drop-down; in other words, that I have KG/Day and not just KG.

2) Eliminate the auto-search behavior that ComboBox wants to do.

I have tried getting in front of these things using method handlers in the Form, such as

ComboBox::DropDown() and ComboBox::DropDownClosed(),

but it seems these still don't allow me to stop the basic ComboBox searching/matching.

I have also tried creating a class of my own inherited from ComboBox, but I don't really know what to override, or in general how to go about getting what I want, stopping what I don't.

So, with that, I thank you for your advice.

EDIT: to expand on what I tried already... In my inherited class, I was attempting to use a WndProc override. Based on some advice I found in another forum, my goal was to intercept the ComboBox message LB_FINDSTRING and replace it with LB_FINDSTRINGEXACT. The post suggested that ComboBox defaulted to LB_FiNDSTRING, which fits what I see it doing, and that subbing LB_FINDSTRINGEXACT would cure the problem. Trouble is, unless I got a bad definition for LB_FINDSTRING, it was never received.

Here's my enum:

[Flags]
public enum ListBoxFlags
{
    LB_ADDSTRING = 0x0180,
    LB_SETSEL = 0x0185,
    LB_GETSELITEMS = 0x0191,
    LB_GETSELCOUNT = 0x0190,
    LB_GETCURSEL = 0x0188,
    LB_SELECTSTRING = 0x018C,
    LB_SETCURSEL = 0x0186,
    LB_FINDSTRING = 0x018F,
    LB_FINDSTRINGEXACT = 0x01A2,
    LB_GETCOUNT = 0x018B,
    LB_GETSEL = 0x0187,
    LB_GETTEXT = 0x0189,
    LB_RESETCONTENT = 0x0184,
    LB_SETHORIZONTALEXTENT = 0x0194,
    LB_GETHORIZONTALEXTENT = 0x0193,
    LB_GETTOPINDEX = 0x018E,
    LB_SETTOPINDEX = 0x0197,
    LB_INSERTSTRING = 0x0181,
    LB_DELETESTRING = 0x0182,
    LB_GETITEMDATA = 0x0199
}
1
What if you changed the DropDownStyle to DropDownList? This will prevent entry of items that are not in the list, however it will still match the items when you type text. The difference is that the text in the combobox is always either empty or an exact match.John Willemse
@JohnWillemse - because such items are permissible in the data. Think of the list as suggestions, not absolute requirements.DonBoitnott
You were on the right track. A combobox consists of three handles, you have to explicitly get the handle to the listbox window. See: stackoverflow.com/questions/25681886/…Loathing
Upvote for Loathing's comment back to the other stack link. It has the correct answer the original poster was looking for. No funky workarounds required.Frog Pr1nce

1 Answers

0
votes

Made some sample code that might help - you can use as a guide.

The idea is to handle the TextChanged event of the ComboBox, and really just modify the ComboBox list items at that point. The example below will modify the list to add the current text (most important, as this will not change the text when you click the combobox) and any other items that meet the search criteria.

I don't think you need the code to re-initialize the list items when focus is lost, but left in there just in case.

    //contains a list of default items for the combobox items
    List<string> comboList = new List<string>();

    public Form1()
    {
        InitializeComponent();
        initComboList(); //initialize the defaults
        initCombobox(); //initialize the combobox list items
    }

    //fills the defaults for the combobox items
    private void initComboList()
    {
        comboList.Add("red");
        comboList.Add("blue");
        comboList.Add("green");
    }

    //initializes the combobox items
    private void initCombobox()
    {
        comboBox1.Items.Clear();
        foreach (string s in comboList)
            comboBox1.Items.Add(s);
    }

    //occurs when the text changes in the combobox
    private void comboBox1_TextChanged(object sender, EventArgs e)
    {
        string curtext = comboBox1.Text;
        insertIntoComboBox(curtext);   //insert the current text into combobox
        comboBox1.Select(curtext.Length, 0); //if you don't do this, the cursor goes back to index 0 :-(
    }

    //called whenever is desired to insert the current text into the combobox items
    private void insertIntoComboBox(string curtext)
    {
        comboBox1.Items.Clear();
        //only add the current text if it's not already in the list of defaults and not empty string
        if (comboList.Contains(curtext) == false && curtext.Length > 0)
            comboBox1.Items.Add(curtext);
        foreach (string s in comboList)
                comboBox1.Items.Add(s);
    }

    //called whenever combobox loses focus
    private void comboBox1_Leave(object sender, EventArgs e)
    {
        initCombobox();
    }