为什么KeyPress的消息框会在KeyDown之前显示?

时间:2015-08-15 00:55:40

标签: c# winforms event-handling

按下文本框中的某个键,KeyDown事件发生在KeyPress之前。

我使用了计数和消息框来查看会发生什么。

以下是我的代码:

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

按下某个键时,会先显示...

KeyPress's Ncount : 2

......紧随其后:

KeyDown's Ncount : 1

KeyDown消息框(带有NCount 1)是否应该在KeyPress消息框(Ncount 2)之前显示?

2 个答案:

答案 0 :(得分:3)

简短版本:MessageBox.Show()是绵羊衣服中臭名昭着的Application.DoEvents狼。绝对比DoEvents更温和,但它并没有解决像这样的重入问题。如果要显示调试信息,请始终使用.NET中的Debug类。

更长版本:要了解这种行为,首先必须了解一个小事实:当您获得KeyDown事件时,操作系统已经生成了KeyPress通知。它耐心地坐在消息队列中,等待您的应用程序恢复调度程序循环。这将是你得到的下一个活动。除非您将e.Handled设置为true,否则Winforms会查看消息队列并清除KeyPress通知,以便事件不会被触发。

下一个factoid:为了使MessageBox成为模态,或者对于任何ShowDialog()调用,它需要运行一个调度程序循环本身。这确保了基本的东西仍然发生,比如绘制窗口和MessageBox识别OK按钮点击并且用户被叮叮当当!当他点击消息框以外的任何其他内容时。

也许你现在可以连接点,MessageBox中的调度程序循环将在队列中看到KeyPress通知。并导致您的KeyPress事件处理程序运行。所以你显示另一个消息框,它必然位于第一个消息框之上。

这里显着错误,副作用就是盒子的Z顺序不是你想要的那个。如果你设置e.Handled = true并期望它能够工作,你会得到更多的戏剧性。它没有赢。它不可能。它已经在您的KeyDown事件处理程序完成时处理。

没有简单的解决方法。但是,一个人,不要使用它。始终使用Debug类生成调试信息。 MessageBox有太多的副作用。

答案 1 :(得分:1)

KeyPressEventArgs指定用户按下键时组成的字符。例如,当用户按下SHIFT + K时,KeyChar属性返回一个大写的K。

当用户按下某个键时会发生KeyPress事件。与KeyPress事件密切相关的两个事件是KeyUp和KeyDown。当用户按下键时,KeyDown事件在每个KeyPress事件之前,当用户释放键时发生KeyUp事件。当用户按下某个键时,每次重复该字符时都会发生重复的KeyDown和KeyPress事件。一个KeyUp事件在发布时生成。

每个KeyPress事件都会传递一个KeyPressEventArgs。 KeyEventArgs与每个KeyDown和KeyUp事件一起传递。 KeyEventArgs指定是否按下任何修改键(CTRL,SHIFT或ALT)和另一个键。 (此修饰符信息也可以通过Control类的ModifierKeys属性获得。)

将Handled设置为true可取消KeyPress事件。这使得控件无法处理按键操作。“

但是也请注意 -

“某些控件将处理KeyDown上的某些击键。例如,RichTextBox在调用KeyPress之前处理Enter键。在这种情况下,您无法取消KeyPress事件,而必须取消KeyDown中的击键。”< / p>

文档很清楚,KeyDown会在KeyPress之前触发,你可以通过这样的编码来显示它:

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

运行它会看到Debug在“按下”之前写入“Down”。你也可以在两个处理程序中断点,看看KeyDown在KeyPress之前触发。

您还会看到“Press”MessageBox在“Down”MessageBox之前显示。这很奇怪,如果有人可以解释,我会感兴趣。

参考:KeyPress Event firing before KeyDown Event on textbox