Pressing a key in a text box, the KeyDown event occurs before KeyPress.
I used a count and message boxes to see what would happen.
The following is my code:
int Ncount = 0;
private void Textbox_KeyDown(object sender, KeyEventArgs e)
{
Ncount += 1;
MessageBox.Show("KeyDown's Ncount : " + Ncount.ToString());
}
private void Textbox_KeyPress(object sender, KeyPressEventArgs e)
{
Ncount += 1;
MessageBox.Show("KeyPress's Ncount : " + Ncount.ToString());
}
When a key is pressed, this will show first...
KeyPress's Ncount : 2
...followed by this:
KeyDown's Ncount : 1
Shouldn't the KeyDown message box (with NCount 1) show before the KeyPress message box (with Ncount 2)?
Short version: MessageBox.Show() is the infamous Application.DoEvents wolf in sheep's clothing. Definitely more benign than DoEvents but it doesn't solve re-entrancy problems like this one. Always use the Debug class in .NET if you want to display debug info.
Longer version: to make sense of this behavior you first have to know a little factoid: by the time you get the KeyDown event, the operating system has already generated the KeyPress notification. It is sitting patiently in the message queue, waiting for your app to resume the dispatcher loop. It will be the next event you get. Unless you set e.Handled to true, then Winforms looks through the message queue and purges the KeyPress notification so the event won't fire.
Next factoid: in order for MessageBox to become modal, or for that matter any ShowDialog() call, it needs to run a dispatcher loop itself. Which ensures that basic stuff still happens, like painting the windows and MessageBox recognizing the OK button click and the user getting slapped with a Ding! when he clicks on anything else but the message box.
Maybe you can connect the dots now, that dispatcher loop in MessageBox will see the KeyPress notification in the queue. And cause your KeyPress event handler to run. So you display another message box, necessarily it is on top of the first one.
Nothing goes dramatically wrong here, the side-effect is just that the Z-order of the boxes is not the one you expect. You'll get a lot more drama if you set e.Handled = true and expect it to work. It won't. It can't. It was already handled by the time your KeyDown event handler completes.
There is no simple fix for this. But one, don't use it. Always use the Debug class to generate debug info. MessageBox has entirely too many side-effects.
A thread on MSDN forums speaks to this oddity:
The event handlers are running in a separate thread. Modal forms are
modal in the context of their own threads.
So whereas message boxes are modal in the form's UI thread, this is not the case for message boxes shown in event handlers.
The message boxes do show in the expected order; they just are not modal per the note above: so they appear to be in the opposite order (when the second/KeyPress message box stacks on top of and covers the first/KeyDown message box).
A variant of your sample code demonstrates what I mean:
int Ncount = 0;
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
Ncount += 1;
var message =
String.Format(
"({0}) KeyDown's Ncount : {1}",
DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture),
Ncount);
Debug.WriteLine(message);
MessageBox.Show(message);
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
Ncount += 1;
var message =
String.Format(
"({0}) KeyPress's Ncount : {1}",
DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture),
Ncount);
Debug.WriteLine(message);
MessageBox.Show(message);
}
It yields the following console output...
(2015-08-15 03:45:31.455) KeyDown's Ncount : 1
(2015-08-15 03:45:31.487) KeyPress's Ncount : 2
...and message boxes in the following unexpected order it would seem...
...but really in the opposite/expected order as the time stamps in the message boxes show.
A KeyPressEventArgs specifies the character that is composed when the user presses a key. For example, when the user presses SHIFT + K, the KeyChar property returns an uppercase K.
A KeyPress event occurs when the user presses a key. Two events that are closely related to the KeyPress event are KeyUp and KeyDown. The KeyDown event precedes each KeyPress event when the user presses a key, and a KeyUp event occurs when the user releases a key. When the user holds down a key, duplicate KeyDown and KeyPress events occur each time the character repeats. One KeyUp event is generated upon release.
With each KeyPress event, a KeyPressEventArgs is passed. A KeyEventArgs is passed with each KeyDown and KeyUp event. A KeyEventArgs specifies whether any modifier keys (CTRL, SHIFT, or ALT) were pressed along with another key. (This modifier information can also be obtained through the ModifierKeys property of the Control class.)
Set Handled to true to cancel the KeyPress event. This keeps the control from processing the key press."
However also note -
"Some controls will process certain key strokes on KeyDown. For example, RichTextBox processes the Enter key before KeyPress is called. In such cases, you cannot cancel the KeyPress event, and must cancel the key stroke from KeyDown instead."
The documentation is clear that KeyDown fires before KeyPress and you can show that it does by coding something like this:
Private Sub TextBox1_KeyDown(sender As Object, e As KeyEventArgs) _
Handles TextBox1.KeyDown
Debug.Print("Down")
MessageBox.Show("Down")
e.Handled = True
End Sub
Private Sub TextBox1_KeyPress(sender As Object, e As KeyPressEventArgs) _
Handles TextBox1.KeyPress
Debug.Print("Press")
MessageBox.Show("Press")
End Sub
Running this you will see that Debug writes "Down" before "Press". You can also but breakpoints in the two handlers and see that KeyDown fires before KeyPress.
You will also see that the "Press" MessageBox shows before the "Down" MessageBox. That is curious and I would be interested if someone could explain it.
Reference: KeyPress Event firing before KeyDown Event on textbox.
Related
I have a TextBox. After leaving the textBox the first character should be a capital Letter.
Three Events work as same. They are Leave,Validating and Validated.
if (txtLocl.Text.Length > 0)
txtLocl.Text = txtLocl.Text.Substring(0, 1).ToUpper() + txtLocl.Text.Substring(1);
Which event of these 3 events should I use?
You can subscribe to the Control.Leave event which will be fired when the control loses focus. Originally, I thought using Control.LostFocus would be the most appropriate event to use but it is not available via the designer meaning you would need to manually subscribe to the event which is a bit ugly and unconventional in my opinion.
private void inputTextBox_Leave(object sender, EventArgs e)
{
if (inputTextBox.Text != string.Empty)
{
string input = inputTextBox.Text;
inputTextBox.Text = input.First().ToString(CultureInfo.InvariantCulture).ToUpper() +
string.Join(string.Empty, input.Skip(1));
}
}
You sound like you're interested in Control.Validating. The advantage of using Control.Validating is that you can utilize the event handler's given argument; CancelEventArgs and set the Cancel property to true. What this will do is stop the control from losing focus and forcing the user to enter a valid value. I don't think this is appropriate for your application as you are not really validating anything but formatting the input.
private void inputTextBox_Validating(object sender, CancelEventArgs e)
{
if (inputTextBox.Text == string.Empty)
{
statusLabel.Text = "The given input is not valid.";
e.Cancel = true;
}
}
Bear in mind that when the form closes, all controls subsequently lose focus and the Control.Validating event is fired which could stop the Form closing until all fields pass their relative validation checks. If you find yourself needing to avoid this behavior a quick search will prevail.
There are many other events also available.
As said by MSDN, When you change the focus by using the keyboard (TAB, SHIFT+TAB, and so on), by calling the Select or SelectNextControl methods, or by setting the ContainerControl.ActiveControl property to the current form, focus events occur in the following order:
1) Enter
2) GotFocus
3) Leave
4) Validating
5) Validated
6) LostFocus
When you change the focus by using the mouse or by calling the Focus method, focus events occur in the following order:
1) Enter
2) GotFocus
3) LostFocus
4) Leave
5) Validating
6) Validated
If the CausesValidation property is set to false, the Validating and Validated events are suppressed.
textBox1_Leave is appropriate for you.
Check the events and description about textboxes over here>>
http://msdn.microsoft.com/en-us/library/system.windows.forms.textbox_events.aspx
Hope its helpful.
You might want to subscribe to LostKeyboardFocus event (in WPF) or Leave event (in WF).
I'd suggest using the Leave because I assume you aren't validating the value, but formatting it. Validating and Validated should contain code for validation and the aftermath of validation respectively, IMO.
I have a custom search activity that serves search suggestions. I get a reference to the search input box and set a handler:
mSearchInput = FindViewById(Resource.Id.searchBoxInput) as EditText;
mSearchInput.KeyPress += new System.EventHandler<View.KeyEventArgs>(OnSearchKeypress);
This is the handler that should be called on every key press:
private void OnSearchKeypress(object sender, View.KeyEventArgs e) {
string query = mSearchInput.Text;
if (e.KeyCode == Keycode.Enter && !string.IsNullOrEmpty(query)) {
e.Handled = true;
// launch search results activity
}
else {
e.Handled = false;
if (query.Length > 2) {
// load suggestions if we have 2+ characters
}
}
}
For some reason, on the soft keyboard, only certain key presses fire the event at all. Enter and Delete fire the event. Alphanumeric keys do not. Even if I take out all of the logic and simply do a Toast with e.KeyCode.ToString() it only shows the toast on those few keys.
Am I listening for the wrong event, is this a bug, or have I made some other mistake?
Device: Droid X2
Mono Version: 4.0.4
Update: I discovered that KeyPress is triggered twice for each physical press of a key: once for KeyEventActions.Up and once for Down. This doesn't explain why only certain keys fire the event but it should be noted that you need to check event.E.Action to find out whether the press or release is currently triggering the event.
When is the event not firing? If it is when the user is typing, then you can use the TextChanged event. You can then continue with your implementation in the OnKey method.
Also, look at this article for the "search" button:
http://www.stackoverflow.com/questions/1489852/android-handle-enter-in-an-edittext
here's my problem .. i'm doing a calculator in C# and i don't want to click every single button to make a operation, i wanna handle it with my num pad .. like
if i press "1" , show me in the textbox "1".
i changed
private void cmd1_Click(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == '1')
{
txtShow.Text='1';
}
}
and i'm having this error :
No overload for 'cmd1_Click' matches delegate "System.EventHandler"
this.cmd1.Click += new System.EventHandler(this.cmd1_Click);
what the hack is wrong with this?
Cheers.
change
this.cmd1.Click += new System.EventHandler(this.cmd1_Click);
to
this.cmd1.KeyPress += new System.EventHandler(this.cmd1_Click);
You'll probably want to rename cmd1_Click too.
And as mentioned in the answer above, this would be better on the Form itself, rather than each button.
You are trying to attach an event handler that corresponds to a KeyPress event to a Click event.
There is something wrong here (bad copy/paste?):
private void cmd1_Click(object sender, KeyPressEventArgs e)
It's named as an auto-generated event handler for the Click event on cmd1, but its definition is the definition for a KeyPress event handler.
Which event do you want to handle? KeyPress or Click or both?
Click is a mouse event, you need to attach to a keyboard event if you want to receive keyboard event args, you'd have to put all your calculator buttons in a common pannel and handle both the button click "and" the text being sent to the panel, that way you could react to both keypresses anywhere and to click for the same result.
An easy way to handling events for all the buttons without doing it one by one is to have a single button click handler and check the text property of the control to know how to act (cast the sender to a button and check the text, do a switch on that)
Not tested:
switch(((button)sender).Text)
{
case "1":
// react to user having pressed 1 etc etc
}
I've tried using the KeyUp and KeyDown events to read keyboard input but as soon as I place other controls on the Winform, the keys are not read. How do I make sure that the keys are read?
You could set KeyPreview = true on your form to catch keyboard events.
EDITED to let you understand:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.A)
e.SuppressKeyPress = true;
}
Stupid sample that receives keyboard events and drop if A was pressed.
If focus is in a textbox, you'll see that text is written, but not A!!
EDITED AGAIN: I took this code from a VB.NET example.
In your usercontrol, use the text box's "Keypress" event to raise a "usercontrol event".
This code would be in your custom usercontrol:
'Declare the event
Event KeyPress(KeyAscii As Integer)
Private Sub Text1_KeyPress(KeyAscii As Integer)
RaiseEvent KeyPress(KeyAscii)
End Sub
See: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.keypreview.aspx
set KeyPreview = true and your KeyUp and KeyDown will recognize all keyboard input.
As marco says set KeyPreview to true on your form to catch the key events in the entire form rather than just a control.
Use the KeyPress event ... KeyUp/Down are more for the framework than your code. KeyDown is good if you want to disable a key ... numeric only fields etc. In general KeyPress is the one you're after.
If you want to prevent the keystrokes from propogating to other controls set KeyPressEventArgs.Handled = true.
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keypress(v=VS.90).aspx
Have you wired up the event handler?
MyForm.KeyDown += MyHandler;
You can also do this in the properties pane ... click the event icon ...
If you are looking for your Form itself to read the keyboard input, you already have your answer from other correspondents. I am adding this contribution for the possibility that you might want to add key handling to other controls or user controls on your form. My article Exploring Secrets of .NET Keystroke Handling published on DevX.com (alas, it does require a registration but it is free) gives you a comprehensive discussion on how and why all the various keyhandling hooks and events come into play. Furthermore, the article includes a "Keystroke Sandbox" utility for free download that actually lets you see which controls are receiving which key handling events.
Here is one illustration from the article to whet your appetite:
I've been working for a while on my Windows Forms project, and I decided to experiment with keyboard shortcuts. After a bit of reading, I figured I had to just write an event handler and bind it to the form's KeyDown event:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.Alt && e.KeyCode == Keys.O)
{
MessageBox.Show("Ctrl+Alt+O: magic!");
}
}
I did that the good ol' way of opening the Properties panel of the Visual Studio designer, then double-clicking on the KeyDown event of my form to generate the Form1_KeyDown event handler. But on testing my application, the form doesn't respond at all to the Ctrl+Alt+O keyboard shortcut. The Visual Studio designer did generate the code to bind the event handler to the form though:
private void InitializeComponent()
{
// ...
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
// ...
}
So I tried adding a Console.WriteLine() call to the handler to check that it was being called at all, but no luck on that either.
Also, I tried to set a breakpoint on the event binding call (shown just above) and found that the program reaches that breakpoint just fine. But any breakpoints I set within the method definition itself are never reached.
To make sure I was doing the first few steps correctly, I tried repeating them with:
A new form in the same solution.
Same issue: the form doesn't respond when I press my Ctrl+Alt+O keyboard shortcut and the debugger isn't even stepping into the event handler. Tried this again and it works.
A brand new WinForms solution.
It works perfectly: the message dialog appears (the Console.WriteLine() call also works).
So I'm quite lost here. What's preventing all the forms in this one project from receiving KeyDown events?
Does your form have KeyPreview property set to true?
Form.KeyPreview Property
Gets or sets a value indicating whether the form will receive key
events before the event is passed to the control that has focus.
http://msdn.microsoft.com/en-us/library/system.windows.forms.form.keypreview.aspx
The most common piece of advice for this problem on StackOverflow and the MSDN1, 2 (including the accepted answer here) is quick and easy:
KeyDown events are triggered on a Form as long as its KeyPreview property is set to true
That's adequate for most purposes, but it's risky for two reasons:
KeyDown handlers do not see all keys. Specifically, "you can't see the kind of keystrokes that are used for navigation. Like the cursor keys and Tab, Escape and Enter for a dialog."
There are a few different ways to intercept key events, and they all happen in sequence. KeyDown is handled last. Hence, KeyPreview isn't much of a preview, and the event could be silenced at a few stops on the way.
(Credit to #HansPassant for those points.)
Instead, override ProcessCmdKey in your Form:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
if (keyData == Keys.Up)
{
// Handle key at form level.
// Do not send event to focused control by returning true.
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
That way, all keys are visible to the method, and the method is first in line to see the event.
Note that you still have control over whether or not focused controls see the KeyDown event. Just return true to block the subsequent KeyDown event, rather than setting KeyPressEventArgs.Handled to true as you would in a KeyDown event handler. Here is an article with more details.
Try setting the KeyPreview property on your form to true. This worked for me for registering key presses.