windows phone 8.1文本框字符virtualKey验证

时间:2014-07-07 14:11:38

标签: c# keyboard winrt-xaml windows-phone-8.1

im develeoping windows phone 8.1 app。 在文本框中,我想阻止用户仅输入任何非数字字母[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更改删除了文本框中的所有内容,我就无法在该文本框中输入任何内容。

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

我在哪里错了?

更新

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

感谢任何帮助

2 个答案:

答案 0 :(得分:7)

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

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

旁注:

我注意到以下问题

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

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

  3. keyBoards

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

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

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

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

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

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

    • 当您将焦点转移到空白文本框时,Shift按钮将会 进入Locked状态(开始用句子判刑) 信件)。所以任何keyDown事件都会首先触发Shift键然后触发 你按的信。如果您不知道,这可能会让您感到困惑 关于它。

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

      

    "跟踪KeyUp和KeyDown作为Shiva的代码建议将起作用   有限的案例,但不是全部。例如,它不会使用墨水或(I   认为)IME输入。它还对键盘布局做出了假设   这对所有键盘都无效。除非你能限制你的   要求非常具体,基本情景的唯一途径   成功限制输入是在事实之后这样做。" Rob Caplan   [MSFT]

    此链接向我保证,唯一可行的方法是接受角色,然后在不适合您的验证时删除它,因此引用:"在事实之后这样做#34;。

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

      

    "改为使用CoreWindow.CharacterReceived"。

    之后我开始搜索,我找到的关于CoreWindow.CharacterReceived的唯一好例子是StackOverflow

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

    <强>解决方案:

    简介:

    • 首先:你不能拦截角色并防止它到达 文本框。

    • 第二:你不能使用keyDown或keyUp事件知道什么是 字符。你只能对按下的按键有所了解 性格结果。

    • 第三:将给你字符接收的事件命名为
      &#34; CoreWindow.CharacterReceived&#34;,但请注意你会知道 将字符写入文本框后。就是在这一点上你 可以选择接受或删除它

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

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

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

    依靠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=="")
        {
    //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;
    }
    

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

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

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

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

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

    如果bool acceptChange为true,则在textChange事件中为

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

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

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

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

    正是在这里,textBox事件的重要性&#34;粘贴&#34;出现了。

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

    txtBox.paste活动中的

    5-确保您通过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 (i.e. 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;
        }
    

    :)

答案 1 :(得分:1)

这是一篇关于MSDN论坛中类似主题的帖子。虽然你可以在事后处理它,但似乎没有好办法防止输入。建议的指南是允许无效输入但不对无效输入做任何事情。例如,允许用户输入一个角色,但不允许他们提交表单。我不一定同意,但如果你必须阻止输入,那么CoreWindow.AcceleratorKeyActivated会很快发生。告诉它是什么角色。&#39;在你的情况下,你只是在寻找数字,所以我认为应该没问题。

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事件。

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

总结中,我无法重现帖子中报告的任何错误。

订阅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;
            }
        }
    }