这是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属性有任何影响?
答案 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
之间的关系提供了很好的解释。