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
删除。在此期间,ShiftState
为NONE
。但是,一旦我使用BACKSPACE
对[ShiftState
]的locked | Down
更改删除了文本框中的所有内容,我就无法在该文本框中输入任何内容。
请注意我从不触摸换档按钮!
我在哪里错了?
更新
我发现使用滑动功能会输入文本字母而不会触发我正在应用的keyDown事件:(
感谢任何帮助
答案 0 :(得分:7)
好的,我会根据我在这里收到的回复并根据我过去几天所做的研究来回答这个问题。答案将分为两个部分[侧面说明 - 解决方案]
如果您对我发现有趣与读者分享的问题的细节不感兴趣,您可以跳转到(解决方案部分)
旁注:
我注意到以下问题
最重要的是窗口8.1和xaml以及winRT 文档非常差,几乎没用。我希望有人 来自微软winRT团队正在阅读此内容。除非他们这样做 这是为了迫使大多数开发人员使用C ++。
关于测试我的申请。我使用了3 [[不同]]输入法。如下图:
,结果与KeyDown事件不同且不兼容,如下所示:
让我假设我想输入字符(&)
我也注意到在物理键盘上,无论你按哪个班次(即向右或向左),KeyDown事件e.Key
都会显示LeftShift
!!
我不知道这是否是我的电脑键盘的特殊情况,但所有这些调查结果都表明keyDown不是真的可信,而且这里缺少文档
另一个发现我注意到我无法控制:
我要感谢@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(接受/不接受)
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;在你的情况下,你只是在寻找数字,所以我认为应该没问题。
我运行了您的代码,并且在删除文本框时没有注意到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;
}
}
}