views:

679

answers:

2

I have a combobox that I don't want users adding new data too, but I also want to let them type in the title of the object they want to select.

Currently I am using this code:

    protected virtual void comboBoxAutoComplete_KeyPress(object sender, KeyPressEventArgs e) {
        if (Char.IsControl(e.KeyChar)) {
            //let it go if it's a control char such as escape, tab, backspace, enter...
            return;
        }
        ComboBox box = ((ComboBox)sender);

        //must get the selected portion only. Otherwise, we append the e.KeyChar to the AutoSuggested value (i.e. we'd never get anywhere)
        string nonSelected = box.Text.Substring(0, box.Text.Length - box.SelectionLength);

        string text = nonSelected + e.KeyChar;
        bool matched = false;
        for (int i = 0; i < box.Items.Count; i++) {
            if (((DataRowView)box.Items[i])[box.DisplayMember].ToString().StartsWith(text, true, null)) {
                //box.SelectedItem = box.Items[i];
                matched = true;
                break;
            }
        }

        //toggle the matched bool because if we set handled to true, it precent's input, and we don't want to prevent
        //input if it's matched.
        e.Handled = !matched;
    }

It works well for any combobox that uses data bound to a database, and is case insensitive. However, if the user inputs something in the wrong case and then tabs out of the combobox the combobox's selected value is still -1 (or whatever the previous value was). That's not the behavior I want, I want it to set the value to what is currently the best guess at what the user is tying, i.e. the autocompleted option.

I have tried this, if you see the commented out line in the for loop. That doesn't work.
It does something like this:
I have the field "Rent" with the value of 53
I type 'r'
I get the result 'rRent'
combobox.SelectedValue returns -1

What it currently does:
I have the field "Rent" with the value of 53
I type 'r'
Autocomplete suggests "rent"
It's the correct value so I move on and the combobox loses focus
Combobox displays "rent"
combobox.SelectedValue return -1

What I want:
I have the field "Rent" with the value of 53
I type 'r'
The combobox loses focus, it fills in 'rent' (even though it's not in the correct case [already does this])
combobox.SelectedValue should now return 53

I think setting box.SelectedValue might be better but I can't figure out how to do that, at least in a high level abstracted way, if I knew how the combobox did it with ValueMemeber and Display member I would duplicate it but I don't.

Does anyone have any suggestions on how to resolve this bug?

+4  A: 

May be barking up the wrong tree, but have you tried just enabling auto complete on the combobox?

comboBox.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
comboBox.AutoCompleteSource = AutoCompleteSource.ListItems;
comboBox.DropDownStyle = ComboBoxStyle.DropDownList;

The last line will limit input to the items in the list.

Thies
Yes I have. But those don't prevent users from typing in new options.
Malfist
Sorry, forgot one important bit; set the DropDownStyle to DropDownList
Thies
A: 

It looks like I have no option but to do it in the LeaveFocus event, this handles the problem:

    protected void autocomplete_LeaveFocus(object sender, EventArgs e) {
        ComboBox box = ((ComboBox)sender);
        String selectedValueText = box.Text;

        //search and locate the selected value case insensitivly and set it as the selected value
        for (int i = 0; i < box.Items.Count; i++) {
            if (((DataRowView)box.Items[i])[box.DisplayMember].ToString().Equals(selectedValueText, StringComparison.InvariantCultureIgnoreCase)) {
                box.SelectedItem = box.Items[i];
                break;
            }
        }
    }
Malfist
Why the down vote?
Malfist