4

I have a situation where I'm provided with a WinForms TextBox instance which I want to attach autocomplete functionality to.

I've got the autocomplete (string matching + dropdown) all figured out and it works reliable so far.

What is the ability to navigate the dropdown with the keyboard (as is the norm with this sort of UI).

The natural solution would be to handle KeyDown (or somesuch) event for the textbox and moving the selection in the dropdown accordingly.

However, it happens that to do this, you need to override the IsInputKey() event to allow capture of arrow key events. The alternative is to override ProcessCmdKey() and handle the event there. The problem with these two is that I cannot override anything since I can't replace the textbox instance.

Edit: Let's assume I have the code below:

void _textBox_KeyDown(object sender, KeyEventArgs e)
{
    if (_dropdown.Visible)
    {
        // TODO The stuff below fails because we need to either handle ProcessCmdKey or override IsInputKey
        switch (e.KeyCode)
        {
            case Keys.Tab:
                {
                    // click selected item
                    _dropdown.Items[GetSelectedItemIndex()].PerformClick();
                    break;
                }
            case Keys.Down:
                {
                    // select next (or first) item
                    int i = GetSelectedItemIndex() + 1;
                    if (i >= _dropdown.Items.Count) i = 0;
                    _dropdown.Items[i].Select();
                    break;
                }
            case Keys.Up:
                {
                    // select previous (or last) item
                    int i = GetSelectedItemIndex() - 1;
                    if (i < 0) i = _dropdown.Items.Count - 1;
                    _dropdown.Items[i].Select();
                    break;
                }
        }
    }
}

Them problem with the code above is that it is never called. The event is never triggered for arrow keys. More info: Up, Down, Left and Right arrow keys do not trigger KeyDown event

Community
  • 1
  • 1
Christian
  • 27,509
  • 17
  • 111
  • 155
  • 2
    You can [preview](https://msdn.microsoft.com/en-us/library/system.windows.forms.form.keypreview.aspx) keys on a `Form` level. Or you can use [keyboard hook](http://blogs.msdn.com/b/toub/archive/2006/05/03/589423.aspx). – Sinatr Jan 23 '15 at 13:33
  • @Sinatr previewing is indeed a possible solution... is there something better? Also, what do you mean by hooks? – Christian Jan 23 '15 at 13:34
  • I don't understand...you have a textbox and a separate drop-down, the latter containing the auto complete entries for the former? Which one will display the entry when it's found? The drop-down? Or will it be loaded into the textbox as well? – rory.ap Jan 23 '15 at 13:40
  • When a user selects the textbox (gives it focus), the dropdown shows. Typing anything changes the values of the dropdown (filters to matching the textbox search query). Pressing the arrow keys changes the dropdown selection and once tab/return is pressed, the textbox gets the value from the dropdown. The problem is that the user cannot currently change the dropdown selection because the textbox doesn't get key events for arrow keys. – Christian Jan 23 '15 at 13:42
  • Hi Christian, do you have a solution for your problem? How did get the dropdown-control of your textbox? – VRage Nov 07 '16 at 06:39

2 Answers2

0

I hope i haven't missunderstood you, but is this a solution:

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Down)
    {
         // Place logic for textbox here
    }
}

I'd use a KeyDown event on the form and then compare the keycode with the Keys.Down keycode

Not working

see here: Up, Down, Left and Right arrow keys do not trigger KeyDown event

Community
  • 1
  • 1
Jens
  • 2,592
  • 2
  • 21
  • 41
0

I may not be understanding your question entirely, but wouldn't an approach like this work?

private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
    comboBox1.Text = //results of your matching algorithm.
}

private void textBox1_Validated(object sender, EventArgs e)
{
    textBox1.Text = (string) comboBox1.Text;
}
rory.ap
  • 34,009
  • 10
  • 83
  • 174