windows phone 8.1文本框字符virtualKeyvalidation

即时通讯windows phone 8.1应用程序。 在文本框中,我想阻止用户仅输入任何非数字字母[0-9]。

所以这是我的代码:

private void NumKeyDown(object sender, KeyRoutedEventArgs e) { bool isNumber = (e.Key == Windows.System.VirtualKey.Number0 || e.Key == VirtualKey.Number1 || e.Key == VirtualKey.Number2 || e.Key == VirtualKey.Number3 || e.Key == VirtualKey.Number4 || e.Key == VirtualKey.Number5 || e.Key == VirtualKey.Number6 || e.Key == VirtualKey.Number7 || e.Key == VirtualKey.Number8 || e.Key == VirtualKey.Number9 || e.Key == VirtualKey.Back); CoreVirtualKeyStates shiftState = Window.Current.CoreWindow.GetKeyState(VirtualKey.Shift); bool shiftIsNotDown = true; if ((shiftState & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down) shiftIsNotDown = false; e.Handled = !(isNumber && shiftIsNotDown); } 

它有效,但有两个主要缺陷:

1-它也接受移位字符(即!@#$%^&*),而不需要。

2-当我启动应用程序时,文本框中填充了一个数字。 我可以输入任何数字或字符(!@#$%^),也可以使用BACKSPACE删除。 在此期间, ShiftStateNONE 。 但是,一旦我使用BACKSPACE删除文本框中的所有内容, ShiftState将更改为[ locked | Down locked | Down ],我无法在该文本框中输入任何内容。

请注意,我从不触摸换档按钮!

我错在哪里?

UPDATE

我发现使用滑动function将输入文本字母而不会触发我正在应用的keyDown事件:(

任何帮助表示赞赏

好的,我会根据我在这里收到的回复并根据我过去几天所做的研究来回答这个问题。 答案将分为两个部分[附注 – 解决方案]

如果您对我发现有趣与读者分享的问题的细节不感兴趣,您可以跳转到(解决方案部分)

附注:

我注意到以下问题

  1. 最重要的是窗口8.1和xaml以及winRT文档非常差,几乎没用。 我希望来自微软winRT团队的人正在阅读这篇文章。 除非他们故意这样做以迫使大多数开发人员使用C ++。

  2. 关于测试我的申请。 我使用了3 [[不同]]输入法。 如下图:

键盘

结果与KeyDown事件不同且不兼容,如下所示:

让我假设我想输入字符(&)

  • 在模拟器键盘上:keyDown eventArg e.Key = Number7。
  • 在PC触控键盘上:KeyDown事件将触发TWICE。 在第一次e.Key代码移位时,在第二次keyDown事件中,e.Key将为Number7
  • 在物理键盘上,两个关键的下降事件将会触发。 你必须先按shift然后按Number7才能得到(&)。

我也注意到在物理键盘上,无论你按哪个class次(即向右或向左),KeyDown事件e.Key都会显示LeftShift !!

我不知道这是否是我的电脑键盘的特殊情况,但所有这些发现都表明keyDown不是真的可信,而且这里缺少文档

另一个发现我注意到我无法控制:

  • 当您将焦点转移到空文本框时,Shift按钮将进入Locked状态(以大写字母开始判断)。 所以任何keyDown事件都会先按Shift键然后按下你按下的字母。 如果您不了解它,这可能会让您感到困惑。

我要感谢@Bryan Stump,带我到微软链接MSFT论坛 ,向我展示了解情况的重要信息:

“跟踪KeyUp和KeyDown,因为Shiva的代码建议适用于有限的情况,但不是全部。例如,它不适用于墨水或(我认为)IME输入。它还假设键盘布局对所有人都无效键盘。除非你能够将你的要求限制在非常具体的基本场景中,否则成功限制输入的唯一方法就是事后这样做。“ Rob Caplan [MSFT]

这个链接向我保证,唯一可行的方法是接受角色然后在不适合你的validation的情况下删除它,因此引用:“事后这样做”。

最后,我要感谢@Hans Passant的简短评论让我走上正轨:

“改用CoreWindow.CharacterReceived”。

之后我开始搜索,我发现关于CoreWindow.CharacterReceived的唯一好例子是在StackOverflow上

从那里开始我的解决方案如下。

解:

介绍:

  • 第一:您无法拦截角色并阻止其到达文本框。

  • 第二:你不能使用keyDown或keyUp事件来知道什么是字符。 你只能知道按下的键而不是字符的结果。

  • 第三:将给你收到字符的事件命名
    “CoreWindow.CharacterReceived”,但请注意你会知道的
    将字符写入文本框后。 此时您可以选择接受或删除它

  • 第四:因为字符在textBox中被收到然后了
    处理它的正确方法是事件textChanged。

  • 第五:最重要的; 是CharacterReceived事件将在单词中的每个字母的循环中触发,这需要特殊的操作和validation

所以根据上面的五个事实,pseudoCode将是:

依靠RegEx来validation文本并接受它; 否则,如果输入无效,则恢复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=="") { //do nothing } else { txtNumber.Text = txtTemp; txtNumber.Select(txtNumber.Text.Length, 0); } //Save the current value to resume it if the next input was invalid txtTemp = txtNumber.Text; } 

以上解决方案适合我的情况,我想确保用户只输入数字。 但是,有些情况下您要确保用户输入特定的字母,您需要根据按下的字母进行响应!! 在这种情况下,您将需要以下解决方案,该解决方案不完整且缺少用户可能从剪贴板输入信件(粘贴)或使用键盘的swypefunction的所有可能方案。

这里是您需要逐字母控制输入的方案的解决方案(按键键):

1-因为CoreWindow.CharacterReceived事件不是特定于CoreWindow.CharacterReceived (它是窗口/页面事件)。 因此,只要文本框获得焦点,您就会将其连接起来。 并且只要文本框失去焦点,就会将其取消。

2-听keyDow event 。 无论何时触发,都将textBox.Text值保存到临时变量txtTemp

3-设置一个布尔值,表示接受的字符是否被接受( bool acceptChange = true )。 并使用CoreWindow.CharacterReceived事件将此布尔值设置为true或false(接受/不接受)

4-在textChange事件中如果bool acceptChange为true,则什么都不做。 如果bool acceptChange为false,则将textBox.Text值重置为您在keyDown事件期间保存的临时值(txtBox.Text = txtTemp)

通过这个解决方案,我们可以确保只接受我们想要的字符,只剩下一个小问题如下:

假设您将validation规则设置为仅接受数字。 和textBox.Text =“752”。 如果用户输入字母“v”,则txtTemp将为“752”并且txtBox.Text的新值将为“752v”,并且在textChange事件中,我们将该值重置为先前值(即“752”)。 这是通过keydown事件的帮助完成的。

但是如果用户没有输入字母“v”但是他从另一个地方复制并使用粘贴function然后使用txtBox.Text =“752v”的新值,但txtTemp将为“75”,因为keYDown甚至没有触发捕获最新的txtBox值:(

正是在这里,textBox事件“粘贴”的重要性出现了。

所以我的伪代码中的第5步是:

txtBox.paste事件中,确保通过使e.Handled=true;取消此事件e.Handled=true;

现在我来到代码:

 //this is critical to wire up the "Window.Current.CoreWindow.CharacterReceived" event when //the textBox get focus and to unwire it when the textBox lose focus. // notice that the whole page is listening not only the textBox 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; } // temporary variable for holding the latest textBox value before the textChange event is trigerred string txtTemp = ""; private void txtBox_KeyDown(object sender, KeyRoutedEventArgs e) { //whenever a key is pressed, capture the latest textBox value txtTemp= txtBox.Text; } // this boolean is to be used by the textChanged event to decide to accept changes or not bool acceptChange = true; // here we recieve the character and decide to accept it or not. private void inputEntered(CoreWindow sender, CharacterReceivedEventArgs args) { // reset the bool to true in case it was set to false in the last call acceptChange = true; Debug.WriteLine("KeyPress " + Convert.ToChar(args.KeyCode)+ "keyCode = "+ args.KeyCode.ToString()); args.Handled = true; //in my case I needed only numeric value and the backSpace button if ((args.KeyCode > 47 && args.KeyCode < 58) || args.KeyCode == 8) { //do nothing (ie acceptChange is still true) } else { //set acceptChange to false bec. character is not numeric nor backSpace acceptChange = false; } } private void txtBox_TextChanged(object sender, TextChangedEventArgs e) { //the code here is my validation where I want only 3 digits number with no decimal if (txtBox.Text.Length < 4) { if (acceptChange) { // do nothing } else { txtBox.Text = txtTemp; //this is to move the cursor to the end of the text in the textBox txtBox.Select(txtBox.Text.Length, 0); } } else { txtBox.Text = txtTemp; //this is to move the cursor to the end of the text in the textBox txtBox.Select(txtBox.Text.Length, 0); } } // this is for the special case where the user input text using Paste function private void txtBox_Paste(object sender, TextControlPasteEventArgs e) { e.Handled=true; } 

🙂

这是一篇关于MSDN论坛中类似主题的post。 似乎没有好的方法来防止输入,尽管你可以在事后处理它。 建议的准则是允许无效输入但不对无效输入做任何事情。 例如,允许用户输入一个字符,但不允许他们提交表单。我不一定同意,但如果你必须阻止输入,那么CoreWindow.AcceleratorKeyActivated会“太早告诉它是什么字符。” 在你的情况下,你只是在寻找数字,所以我认为它应该没问题。

http://social.msdn.microsoft.com/Forums/windowsapps/en-US/3c0f5251-9356-4f1d-a148-57024ae71724/testing-for-valid-numeric-and-currency-key-strokes?forum=winappswithcsharp

我运行了您的代码,并且在删除文本框时没有注意到Shift键状态切换。

我还使用了屏幕键盘并确实收到了KeyDown事件。

此外,您的代码也不接受转移的字符!@#$%。

在摘要中,我无法重现post中报告的任何错误。

订阅CoreWindow.AcceleratorKeyActivated事件。 您可以检查VirtualKey。 此事件发生在TextBox.TextChanged之前,因此我们使用此方法通过过滤按下文本框将处理的按键来利用路由事件框架。

  public MainPage() { this.InitializeComponent(); Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated += Dispatcher_AcceleratorKeyActivated; } void Dispatcher_AcceleratorKeyActivated(CoreDispatcher sender, AcceleratorKeyEventArgs args) { if (MyTextBox.FocusState != FocusState.Unfocused) { if (args.VirtualKey == VirtualKey.Number0 || args.VirtualKey == VirtualKey.Number1 || args.VirtualKey == VirtualKey.Number2 || args.VirtualKey == VirtualKey.Number3 || args.VirtualKey == VirtualKey.Number4 || args.VirtualKey == VirtualKey.Number5 || args.VirtualKey == VirtualKey.Number6 || args.VirtualKey == VirtualKey.Number7 || args.VirtualKey == VirtualKey.Number8 || args.VirtualKey == VirtualKey.Number9) { args.Handled = false; } else { args.Handled = true; } } }