为什么MessageBox对SuppressKeyPress有影响?

时间:2014-08-01 17:16:24

标签: vb.net key

这是vb中的一个特殊情况。我弄乱了SuppressKeyPress属性,我发现了一些奇怪的东西。

情况

假设我有一个名为txtName的文本框,我希望名称没有任何数字,当插入一个数字时,会弹出一个MessageBox并报告错误。

Private Sub TextBox1_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles txtName.KeyDown
    If e.KeyCode >= Keys.D0 And e.KeyCode <= Keys.D9 And _
e.Modifiers <> Keys.Shift Then
        e.SuppressKeyPress = True
        MsgBox("Error - A Number has been pressed")
        'The number appeared in the text box.
    End If
End Sub

在这种情况下,由于一些奇怪的原因,如果我输入一个数字,它将写在文本框中,虽然我压制了按键。

我发现如果删除MsgBox行,该号码将不会出现在文本框中。

Private Sub TextBox1_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles txtName.KeyDown
    If e.KeyCode >= Keys.D0 And e.KeyCode <= Keys.D9 And _
e.Modifiers <> Keys.Shift Then
        e.SuppressKeyPress = True
        'The number did not appear in the text box.
    End If
End Sub

问题

发生了什么事?为什么MsgBox&#34;允许&#34;要按的关键?为什么它对SuppressKeyPress属性有任何影响?

3 个答案:

答案 0 :(得分:2)

这是使用MessageBox的一个非常典型的副作用,它可能会导致许多棘手的问题。通过在消息队列中搜索任何按键事件并删除它们来实现 SuppressKeyPress 属性。但这只能在事件处理程序完成后 时发生。

麻烦的是,它不会很快完成。你的MsgBox()调用正在接管,它开始自己抽取一个消息循环。就像对话框一样,相当于调用臭名昭着的DoEvents()方法。它会很容易地在消息队列中调度待处理的消息,包括那些应该被抑制的按键消息。

此类问题的创可贴是在事件处理完成后Winforms有机会清除按键消息后显示消息框以后。使用Control.BeginInvoke()方法优雅地完成:

Private Sub TextBox1_KeyDown(sender As Object, e As KeyEventArgs) Handles TextBox1.KeyDown
    If e.KeyCode >= Keys.D0 And e.KeyCode <= Keys.D9 And e.Modifiers <> Keys.Shift Then
        e.SuppressKeyPress = True
        Me.BeginInvoke(New Action(Sub() MsgBox("Error - A Number has been pressed")))
    End If
End Sub

真正的修复是使用正确的事件。您应该始终使用KeyPress事件来进行此类过滤。这也避免了在使用KeyDown时对用户的活动键盘布局非常痛苦的依赖。修正:

Private Sub TextBox1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox1.KeyPress
    If e.KeyChar >= "0"c AndAlso e.KeyChar <= "9"c Then
        e.Handled = True
        MsgBox("I don't like digits")
    End If
End Sub

但话说回来,不要使用消息框来打击用户犯下一个简单的错误。

答案 1 :(得分:1)

对于那些不想弄乱调用方法,手动启动新线程等的人,我发现了一些“ hack”。

我无效的(旧)代码是

Private Sub textEditKeyPress(ByVal sender As Object, ByVal e As KeyEventArgs)
    If e.KeyValue = 220 Then
        e.SuppressKeyPress = True
        MessageBox.Show("\ not allowed. Use / instead.")
    End If
End Sub

通过将代码更改为

Private Async Sub tEditDropBoxFolderName_EditValueChanged(ByVal sender As Object, ByVal e As KeyEventArgs)
    If e.KeyValue = 220 Then
        e.SuppressKeyPress = True
        Await Task.Delay(100)
        MessageBox.Show("\ not allowed. Use / instead.")
    End If
End Sub

一切正常,我还没有发现任何副作用。

(代码由c#翻译,也许需要对vb进行一些修改。)

答案 2 :(得分:0)

所以我测试了你的代码,我可以重现这种行为。我认为发生这种情况的原因是因为MsgBox(模态对话框)将调用Application.DoEvents导致消息被处理。

替换

MsgBox("Error - A Number has been pressed")

Application.DoEvents

你会得到相同的结果。


您应该在以下SO帖子中阅读 Hans Passant的答案。他对ShowDialog (参考MsgBox)DoEvents之间的关系提供了很好的解释。