windows phone 8.1文本框字符virtualKey验证

sta*_*low 4 c# keyboard winrt-xaml windows-phone-8.1

即时通讯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);

        }
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

我在哪里错了?

UPDATE

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

任何帮助表示赞赏

sta*_*low 7

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

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

附注:

我注意到以下问题

  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才能得到(&).

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

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

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

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

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

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

这个链接向我保证,唯一可行的方法是接受角色,然后删除它,如果不适合你的验证,因此引用:"事后这样做".

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

"改用CoreWindow.CharacterReceived".

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

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

解:

介绍:

  • 第一:你不能拦截角色并阻止它到达文本框.

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

  • 第三:将为您提供字符接收的事件被命名为
    "CoreWindow.CharacterReceived",但请注意在将
    字符写入文本框后您将知道该字符.此时您可以选择接受或删除它

  • 第四:由于字符在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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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)

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

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

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

正是在这里,textBox事件"粘贴"的重要性出现了.

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

5- txtBox.paste如果确保您通过制作取消此活动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;
    }
Run Code Online (Sandbox Code Playgroud)

:)