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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With