Handling arrow key events on a winform textbox without overriding - c#

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

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

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;
}

Related

C# Detect when key gets pressed and trigger a button

So I'm trying to make a simple calculator. The user can only input the numbers by the buttons on the form or by the numpad. This is the code I have:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
string key = "";
switch (e.KeyCode)
{
case (Keys.NumPad1):
key = "1";
break;
case (Keys.NumPad2):
key = "2";
break;
default:
break;
}
txt_string.Text = txt_string.Text + key;
}
If I make a breakpoint on the KeyDown function and press the Numpad keys (and every other keys) the program doesnt even comes to that breakpoint.
Do I have to change something on my Form to detect the Keys?
You'll need to set KeyPreview to true (property on the form). Also, I would advise against trying to debug the behaviour - because you may affect the behaviour you're testing (Debug.WriteLine()) is your friend here.
Just to point out that many keyboard doesnt have numpad. You can check if the key is a integer.
void Form1_KeyDown(object sender, KeyPressEventArgs e)
{
if (char.IsDigit(e.KeyChar))
{
txt_string.Text += e.KeyChar;
}
}
This is more a Code Review than a solution though.

WinForms listbox keydown event won't fire

I am trying to make a WinForm ListBox in which you can loop trough using the arrow keys. I also have two buttons on which you can click to go up and down the list. The buttons do produce the desired effect. The problem is that the ListBox's keyDown event is never triggered
public MainForm()
{
InitializeComponent();
if (this.clipboardHistoryList.Items.Count > 0)
this.clipboardHistoryList.SetSelected(0, true);
clipboardHistoryList.Select();
}
private void goUpButton_Click(object sender, EventArgs e)
{
goUpList();
}
private void goDownButton_Click(object sender, EventArgs e)
{
goDownList();
}
private void goDownList()
{
if (clipboardHistoryList.SelectedIndex == clipboardHistoryList.Items.Count - 1)
{
clipboardHistoryList.SetSelected(0, true);
}
else
{
clipboardHistoryList.SetSelected(clipboardHistoryList.SelectedIndex + 1, true);
}
}
private void goUpList()
{
if (clipboardHistoryList.SelectedIndex == 0)
{
clipboardHistoryList.SetSelected(clipboardHistoryList.Items.Count - 1, true);
}
else
{
int l_currentlySelected = clipboardHistoryList.SelectedIndex;
clipboardHistoryList.SetSelected(l_currentlySelected - 1, true);
}
}
private void clipboardHistoryList_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Up) //Brekpoint is never reached
{
goUpList();
}
else if (e.KeyCode == Keys.Down)
{
goDownList();
}
}
I have put the MainForm's keypreview proprety to true.
The arrow keys do work by default on a listbox but they won't let you go from last to first element if you press the down arrow on the last element --hopes this makes sense.
EDIT
I have seen on Microsoft's documentation that I need to override the ProcessDialogKey method but I am not exactly sure of what I need to do.
Perform special input or navigation handling on a control. For example, you want the use of arrow keys in your list control to change the selected item. Override ProcessDialogKey
Is there already a built-in way to enable this behaviour?
What did I miss?
Thanks!
From looking at the code in your Designer.cs file, it doesn't look like you've actually got your clipboardHistoryList control wired into your clipboardHistoryList_KeyDown event handler. You can do that through the "Events" subtab of the Properties window in your visual studio form designer (look for the little lightning bolt icon) and wire up the event through the designer that way, or alternatively you can do it in code:
public MainForm()
{
InitializeComponent();
if (this.clipboardHistoryList.Items.Count > 0)
this.clipboardHistoryList.SetSelected(0, true);
clipboardHistoryList.Select();
clipboardHistoryList.KeyDown += clipboardHistoryList_KeyDown;
}

Capture Tab KeyUp on a winrt textbox

I am building a XAML app (winrt) to be used in enterprise. Some forms in the app can be complex: some inputs gets shown/hidden depending on other inputs. I would like to control the tab key navigation using a behavior on all inputs (TextBox, PasswordBow, ComboBox...) to optimize the user activity.
I subscribed to the KeyUp event of the TextBox but the event is not raised when the user strikes the Tab key. As a consequence, the next element in the visual tree is given keyboard focus.
I found not method to override like the winform's IsInputKey.
How can I subscribe to the use of the Tab key on a TextBox?
Is looks like the newly focus element receives the KeyUp event.
What I did is subscribe to the KeyDown event, checked for the Tab key and marked the event as handled.
protected override void OnAttached()
{
var textBox = (TextBox)this.AssociatedObject;
textBox.KeyDown += this.OnKeyDown;
textBox.KeyUp += this.OnKeyUp;
// don't forget to unsubscribe in OnDetached
}
private void OnKeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == VirtualKey.Tab && !e.Handled)
{
e.Handled = this.Work(sender, e);
}
}
private void OnKeyUp(object sender, KeyRoutedEventArgs e)
{
if (e.Key != VirtualKey.Tab && !e.Handled)
{
e.Handled = this.Work(sender, e);
}
}
Here is the method that does the focusing work. The code was in OnKeyUp before I knew how to do.
/// <returns>true if an action has been performed (focus next or execute command)</returns>
private bool Work(object sender, KeyRoutedEventArgs e)
{
var isEnterKey = e.Key == VirtualKey.Enter;
var isTabKey = e.Key == VirtualKey.Tab;
if (/* there is something else to focus */)
{
// focus it
return true;
}
return false;
}
My problem was that the Tab virtual key wasn't being received in the KeyUp event, while other keys (Esc,Enter, alphanumeric keys) were. I just changed it to a KeyDown with the same handler. The difference seems to be imperceptible to the user.

Are some keyboards more loquacious than others?

The lead developer says that when he uses my app, his keyboard beeps when he moves between TextBoxes on the TableLayoutPanel via the directional arrow keys.
However, I hear no such aural activity.
Here's my code:
// Had to intercept Up and Down arrows from Windows
private void textBoxPlatypi_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) {
TextBox tb = (TextBox)sender;
if (e.KeyCode.Equals(Keys.Up)) {
SetFocusOneRowUp(tb.Name);
return;
}
if (e.KeyCode.Equals(Keys.Down)) {
SetFocusOneRowDown(tb.Name);
return;
}
}
private void textBoxPlatypi_KeyDown(object sender, KeyEventArgs e) {
TextBox tb = (TextBox)sender;
if (e.KeyCode.Equals(Keys.Left)) {
SetFocusOneColumnBack(tb.Name);
e.Handled = true;
return;
}
if (e.KeyCode.Equals(Keys.Right)) {
SetFocusOneColumnForward(tb.Name);
e.Handled = true;
return;
}
}
..He thought maybe I needed "e.Handled" but that is not available in the PreviewKeyDown event.
Is there a way to suppress the beeping (which apparently occurs only with certain keyboards or specific setups (he's using Windows7, I'm on XP still))?
UPDATE
I've got this code now:
private void textBoxPlatypus1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) {
switch (e.KeyCode) {
case Keys.Down:
case Keys.Up:
e.IsInputKey = true;
break;
}
}
private void textBoxPlatypus1_KeyDown(object sender, KeyEventArgs e) {
TextBox tb = (TextBox)sender;
if (e.KeyCode.Equals(Keys.Up)) {
SetFocusOneRowUp(tb.Name);
e.Handled = true;
return;
}
if (e.KeyCode.Equals(Keys.Down)) {
SetFocusOneRowDown(tb.Name);
e.Handled = true;
return;
}
if (e.KeyCode.Equals(Keys.Left)) {
SetFocusOneColumnBack(tb.Name);
e.Handled = true;
return;
}
if (e.KeyCode.Equals(Keys.Right)) {
SetFocusOneColumnForward(tb.Name);
e.Handled = true;
return;
}
}
...but he still hears the beeping (I don't).
He's in Alaska and using Windows 7; I'm in California and using XP. I don't know if some combination/mismatch there is the problem...
UPDATED AGAIN
I know this may be shocking to some, but the Alaska/California disconnection has nothing to do with it. I'm now hearing the beeps, too, and it's not from the arrow keys. It's when a value is entered in a TextBox and then, if that text box already has a character, focus is moved to the next textBox and the value is entered there (this is my code that causes this to happen). But the irritating beeping seems to be random - I haven't figured out the pattern for when it beeps (sometimes it does, sometimes it doesn't)...has anybody ever run across anything like that, or, better yet, know how to suppress the beep? All I'm doing is pressing either the "1" or the "2" key above the keyboard.
There is no way in the PreviewKeyDownEvent to Handle / Supress a KeyEvent like there is in the normal KeyDown Event. What the documentation suggests is to set the PreviewKeyDownEventArgs.IsInputKey property to true in order to handle key presses that are not available normally in the KeyDown Event.
From above Link, they are using a button as an example:
Some key presses, such as the TAB, RETURN, ESC, and arrow keys, are typically ignored by some controls because they are not considered input key presses... By handling the PreviewKeyDown event for a Button and setting the IsInputKey property to true, you can raise the KeyDown event when the arrow keys are pressed. However, if you handle the arrow keys, the focus will no longer move to the previous or next control.
Try this:
e.SuppressKeyPress = true;

Key down event on the slider in C#

I wanted to handle Arrow key press event on the slider control. I tried googling for it but almost all the links gave me information about handling it on the windows(overrideing WndProc or ProcessCmdKey).The KeyDwon and Key Up events aren't fired for the Arrow press. How can i handle it?
Look here.
Here's a short quote from there:
Certain keys, such as the TAB, RETURN, ESC, and arrow keys are handled by controls automatically. To have these keys raise the KeyDown event, you must override the IsInputKey method in each control on your form. The code for the override of the IsInputKey would need to determine if one of the special keys is pressed and return a value of true. Instead of overriding the IsInputKey method, you can handle the PreviewKeyDown event and set the IsInputKey property to true. For a code example, see the PreviewKeyDown event.
And here's the code sample from the PreviewKeyDown event from here (PreviewKeyDown):
// By default, KeyDown does not fire for the ARROW keys
void button1_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Down:
case Keys.Up:
if (button1.ContextMenuStrip != null)
{
button1.ContextMenuStrip.Show(button1,
new Point(0, button1.Height), ToolStripDropDownDirection.BelowRight);
}
break;
}
}
// PreviewKeyDown is where you preview the key.
// Do not put any logic here, instead use the
// KeyDown event after setting IsInputKey to true.
private void button1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Down:
case Keys.Up:
e.IsInputKey = true;
break;
}
}
I'm presuming you're using a track bar control when you say slider control? If not, then this answer probably won't help.
Anyway, you need to set the OnKeyDown event for your track bar control. Something as simple as the following code will allow the user to use the left and right arrows to move from side to side.
private void trackBar1_KeyDown(object sender, KeyEventArgs e)
{
if ((e.KeyCode == Keys.Right) && (trackBar1.Value < trackBar1.Maximum))
trackBar1.Value += 1;
if ((e.KeyCode == Keys.Left) && (trackBar1.Value > trackBar1.Maximum))
trackBar1.Value -= 1;
}
You simply need to detect a key press, and then decide whether it's a left or right arrow, and then what to do from there.
I've tried it and the left and right arrows do trigger it for me. Again, if you're using a different slider control (there isn't any control called the slider control, so I'm assuming track bar) then it may be different.

Categories