好的,根据我在这里收到的回复和最近几天的研究,我会尝试回答这个问题。答案将分为两个部分[附注-解决方案]
如果您对我发现有趣的问题的细节不感兴趣,可以跳转到(解决方案部分)
附注:
我注意到以下问题:
最重要的是,window 8.1和xaml和winRT文档非常差,几乎没有用处。我希望微软winRT团队中的某人正在阅读这篇文章。除非他们故意这样做以迫使大多数开发人员转向C ++。
关于测试我的应用程序。我使用了3种[[不同]]输入方法。如下图所示:
结果与KeyDown事件不同且不一致,如下所示:
假设我想输入字符(&)。
- 在模拟器键盘上:keyDown事件参数e.Key = Number7。
- 在PC触摸键盘上:KeyDown事件将会触发两次。第一次按下时,e.Key代码将为shift,在第二个keyDown事件中,e.Key将是Number7。
- 在物理键盘上,当然会触发两个keyDown事件,因为您必须先按shift,然后按Number7才能得到(&)。
此外,我注意到在物理键盘上,无论按哪个shift键(即右侧或左侧),KeyDown事件的e.Key
都会显示LeftShift
!!
我不知道这是否是我的计算机键盘的特殊情况,但所有这些发现都表明,KeyDown不是真正可信赖的,文档在这里缺乏。
还有另一个我注意到无法控制的发现:
- 每当您将焦点放在空文本框上时,Shift键将进入锁定状态(以大写字母开始句子)。因此,任何keyDown事件都会首先触发Shift键,然后才是您按下的字母。如果您不知道这一点,可能会感到困惑。
我要感谢@Bryan Stump,他带我去了微软链接MSFT Forum,在那里我了解到了重要的信息,以理解这种情况:
"跟踪KeyUp和KeyDown,如Shiva代码所建议的,将适用于有限的情况,但并非所有情况。例如,它无法与墨水或(我认为)IME输入配合使用。它还对键盘布局做出了假设,这些假设并不适用于所有键盘。除非您可以将要求限制在非常具体、基本的场景中,否则成功地限制输入的唯一方法是在事后这样做。" Rob Caplan [MSFT]
这个链接告诉我,唯一可行的方法是先接受字符,然后在不符合验证要求时将其删除,因此引用了“事后”这句话。
最后,我想感谢@Hans Passant的简短评论,让我找到了正确的方向:
“使用CoreWindow.CharacterReceived代替”。
之后,我开始搜索,关于CoreWindow.CharacterReceived唯一好的例子是在
StackOverflow上找到的。
然后,我按照以下方式解决了问题。
解决方案:
介绍:
首先:您无法拦截字符并防止其到达文本框。
其次:您无法使用keyDown或keyUp事件来知道是什么字符。您只能对按下的键有一个想法,而不是产生的字符。
第三:将为您提供接收字符的事件命名为“CoreWindow.CharacterReceived”,但请注意,您将在将字符写入文本框后才会知道字符。在这一点上,您可以选择接受它或删除它
第四:由于字符是在textBox中接收的,因此处理它的正确方法是textChanged事件。
第五:最重要的是,CharacterReceived
事件将在单词中的每个字母上循环触发,这需要特殊的操作和验证
因此,基于以上五个事实,伪代码将如下:
依靠RegEx验证文本并接受它;否则,如果输入无效,则恢复textBox.Text
的先前状态。
string txtTemp = "";
private void changedText(object sender, TextChangedEventArgs e)
{
Regex regex = new Regex(@"^\d{1,4}$");
string txtToTest = txtNumber.Text;
if (regex.IsMatch(txtToTest)|| txtNumber.Text=="")
{
}
else
{
txtNumber.Text = txtTemp;
txtNumber.Select(txtNumber.Text.Length, 0);
}
txtTemp = txtNumber.Text;
}
上述解决方案适用于我需要确保用户只输入数字的情况。但是有些情况下,您需要确保用户只输入特定字母,并且您需要根据按下的字母做出响应!!在这种情况下,您将需要以下解决方案,该解决方案不完整,并且缺乏用户可能从剪贴板(粘贴)或使用键盘的滑动功能输入字母的所有可能情况。
以下是需要逐个控制输入字母的场景的解决方案:
1-由于CoreWindow.CharacterReceived事件不特定于textBox(它是窗口/页面事件),因此您需要在textBox获得焦点时连接它,并在textBox失去焦点时断开连接。
2-监听keyDown事件。每当它被触发时,将
textBox.Text
值保存到临时变量
txtTemp
中。
3-设置一个布尔值,指示字符是否被接受(
bool acceptChange = true
)。并使用CoreWindow.CharacterReceived事件将此布尔值设置为true或false(已接受/未接受)。
在textChange事件中,如果bool类型的acceptChange为true,则不做任何操作。如果bool类型的acceptChange为false,则将textBox.Text的值重置为keyDown事件期间保存的临时值(txtBox.Text = txtTemp)。
通过这种解决方案,我们可以确保只接受我们想要的字符,只剩下一个微小的问题:
假设您设置了验证规则,仅接受数字。而textBox.Text =“752”。
如果用户输入字母“v”,则txtTemp将为“752”,txtBox.Text的新值将为“752v”,在textChange事件中,我们将将该值重置为先前的值(即“752”)。这是通过keyDown事件的帮助完成的。
但是,如果用户没有键入字母“v”,而是从其他地方复制并使用粘贴功能,则txtBox.Text的新值为“752v”,但txtTemp将为“75”,因为keyDown事件未触发以捕获最新的txtBox值:(
这就是textBox事件“paste”的重要性所在。
因此,我的伪代码中的第5步是:
在txtBox.paste
事件中,确保通过将e.Handled=true;
来取消此事件。
现在我来到代码:
private void txtBox_GotFocus(object sender, RoutedEventArgs e)
{
Window.Current.CoreWindow.CharacterReceived += inputEntered;
}
private void txtBox_LostFocus(object sender, RoutedEventArgs e)
{
Window.Current.CoreWindow.CharacterReceived -= inputEntered;
}
string txtTemp = "";
private void txtBox_KeyDown(object sender, KeyRoutedEventArgs e)
{
txtTemp= txtBox.Text;
}
bool acceptChange = true;
private void inputEntered(CoreWindow sender, CharacterReceivedEventArgs args)
{
acceptChange = true;
Debug.WriteLine("KeyPress " + Convert.ToChar(args.KeyCode)+ "keyCode = "+ args.KeyCode.ToString());
args.Handled = true;
if ((args.KeyCode > 47 && args.KeyCode < 58) || args.KeyCode == 8)
{
}
else
{
acceptChange = false;
}
}
private void txtBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (txtBox.Text.Length < 4)
{
if (acceptChange)
{
}
else
{
txtBox.Text = txtTemp;
txtBox.Select(txtBox.Text.Length, 0);
}
}
else
{
txtBox.Text = txtTemp;
txtBox.Select(txtBox.Text.Length, 0);
}
}
private void txtBox_Paste(object sender, TextControlPasteEventArgs e)
{
e.Handled=true;
}
:)
InputScope="Number"
来限制输入吗?或者你坚持要全键盘? - Romasz