views:

1308

answers:

2

How can I allow the users of my program to type in a value and have it auto-complete, however, I also what to prevent them from entering new data because it would cause the data to be unfindable (unless you had direct access to the database).

Does anyone know how to do this?

The reasoning behind not using just a dropdown style combobox is because entering data by typing it is and then refusing characters that are not part of an option in the list is because it's easier on the user.

If you have used Quickbook's Timer, that is the style of comboboxes I am going for.

+1  A: 

OK, here's what I came up with. Hack? Maybe, but hey, it works. I just filled the combobox with the days of the week (hey, I needed something), and then handle the keypress event. On every key press, I check if that word matches the begining of any word in the AutoCompleteSourceCollection. If it doesn't, I set e.Handled to true, so the key doesn't get registered.

    public Form5()
    {
        InitializeComponent();

        foreach (var e in Enum.GetValues(typeof(DayOfWeek)))
        {
            this.comboBox1.AutoCompleteCustomSource.Add(e.ToString());
        }

        this.comboBox1.KeyPress += new KeyPressEventHandler(comboBox1_KeyPress);

    }

    private void comboBox1_KeyPress(object sender, KeyPressEventArgs e)
    {
        string text = this.comboBox1.Text + e.KeyChar;
        e.Handled =  !(this.comboBox1.AutoCompleteCustomSource.Cast<string>()
           .Any(s => s.ToUpperInvariant().StartsWith(text.ToUpperInvariant()))) && !char.IsControl(e.KeyChar);
    }

EDIT: If you're on .Net 3.5 you'll need to reference System.Linq. If you're on .NET 2.0 then use this instead:

    private void comboBox1_KeyPress(object sender, KeyPressEventArgs e)
    {
        string text = this.comboBox1.Text + e.KeyChar;
       foreach (string s in this.comboBox1.AutoCompleteCustomSource)
        {
            if (s.ToUpperInvariant().StartsWith(text.ToUpperInvariant()))
            {
                return;
            }
        }
        e.Handled = true;

    }
BFree
Error 1 'System.Windows.Forms.AutoCompleteStringCollection' does not contain a definition for 'Cast' and no extension method 'Cast' accepting a first argument of type 'System.Windows.Forms.AutoCompleteStringCollection' could be found (are you missing a using directive or an assembly reference?)
Malfist
I have .NET 3.5 SP1 but I don't have System.Linq
Malfist
I am using VS 2008 with .NET 3.5
Malfist
Ah project properties has this project set to target .NET 2.0
Malfist
So, did it work for you?
BFree
No, I'm not using a CustomSource, and AutoCompleteSource doesn't seem to act as an array...looking for a work around.
Malfist
+1  A: 

Kudos to BFree for the help, but this is the solution I was looking for. The ComboBox is using a DataSet as it's source so it's not a custom source.

    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)) {
                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;
    }
Malfist
Do yourself a favor, and at the top of your method do this:ComboBox comboBox = sender as ComboBox. Then you won't have to to the casting 1000 times. Casting == overhead.
BFree
Fixed, thank you!
Malfist
I was looking for this exact thing. However, the above solution does not help. I am still not able to restrict the text in the dropdown to the listitems.What might I be doing wrong?
rAm
I don't know, but I've changed it so maybe this version will work better.
Malfist