Well, I will try to answer this question based on the answers I received here and based on the studies that I have spent the last couple of days. The answer will consist of two sections [Side Notes - solution]
You can go to the "Solution" section if you are not interested in the details of the problems that I am interested in sharing with readers.
Side notes:
I noticed the following problems
most important is that the 8.1 window and xaml and winRT documentation are extremely poor and almost useless. I hope someone from the Microsoft winRT team reads this. If they do not do this specifically in order to get most developers to switch to C ++.
regarding testing my application. I used 3 [[different]] input methods. as shown in the following figure:

and the result was different and inconsistent with the KeyDown event as follows:
let me assume that I want to enter a character (&)
- on the emulator keyboard: keyDown eventArg e.Key = Number7.
- on the PC touch keyboard: the KeyDown event will fire TWICE. in the first time the e.Key code will be a shift, and in the second keyDown the e.Key event will be Number7
- on the physical keyboard, which will trigger two keyDown events. you need to press shift first, then Number7 to get (&).
I also noticed on the physical keyboard that no matter which shift you press (i.e., left or right), the KeyDown e.Key event will show LeftShift !!
I donβt know if this was a special case for my computer keyboard, but all these conclusions show that keyDown is not really reliable, and there is no documentation here.
Another conclusion that I noticed that I could not control:
- When you get focus on an empty text box, the Shift button will enter the Locked status (to start the offer with a capital letter). therefore, any keyDown event fires the Shift key first, then the letter you pressed. it may confuse you if you do not know about it.
I would like to thank @Bryan Stump for taking me to the Microsoft MSFT forum link in which I found important information to understand the situation
"Tracking KeyUp and KeyDown, as the Shiva code suggests, will work in limited cases, but not all. For example, it will not work with ink or (I think) IME input. It also makes assumptions about the keyboard layout that are not suitable for all keyboards. If you cannot limit your requirements to very specific, basic scenarios, the only way to successfully limit your input is to do it after the fact. " Rob Kaplan [MSFT]
This link assured me that the only available way is to accept the character, and then delete it if it is not suitable for your verification, so the quote is "do it after the fact."
and finally, I would like to thank @Hans Passant for his short comment, which set me on the right track:
"Use CoreWindow.CharacterReceived instead."
after that I started looking and the only good example I found regarding CoreWindow.CharacterReceived is at fooobar.com/questions/945977 / ...
and from there I began my decision as follows.
Decision:
Introduction:
Firstly: you cannot intercept a character and prevent his text field.
Secondly: you cannot use keyDown or keyUp events to find out what a character is. you can only have an idea of ββthe keystroke, not the character.
Third: an event that will give you a character is called
"CoreWindow.CharacterReceived", but note that you will find out how after writing it in the text box. it is at this point that you can accept it or delete it.
Fourth: since the character is received in the text field, then the correct way to deal with it is the textChanged event.
Fifth: and most importantly; that the CharacterReceived event will be a fire in the loop on each letter in the word, and this requires special maneuver and validation
therefore, based on five facts above the pseudo-code will be:
rely on RegEx to validate and accept text; otherwise, if the input is invalid, then resume the previous state of 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=="") {
The above solution is suitable for my case when I want to make sure that the user will enter only numbers. However, there are cases when you want to make sure that the user will enter a specific letter, and you need to answer based on the letter! In this case, you will need the following solution, which is incomplete and does not have all the possible scenarios when the user can enter a letter from the clipboard (Paste) or using the swype functions on the keyboard.
Here is the solution for the scenario in which you need to control the letter of the letter input (key with key):
1-, since the CoreWindow.CharacterReceived event is not specific to the textBox (this is a window / page event). therefore, you will be connected to it every time your text field receives focus. and avoid it whenever your text box loses focus.
2- listen to keyDow event . each time you start, save the value of textBox.Text in the temporary variable txtTemp .
3- set a boolean value indicating that the received character is accepted or not ( bool acceptChange = true ). and using the CoreWindow.CharacterReceived event, set the boolean value to true or false (accepted / not accepted)
4- in the textChange event, if the bool acceptChange is true, then do nothing. If the bool acceptChange value is false, then reset the textBox.Text value for the temporary value that you saved during the keyDown event (txtBox.Text = txtTemp)
with this solution, we can make sure that we accept only the character that we need, with only one tiny problem remaining:
Suppose you set up validation rules to accept only numbers. and textBox.Text = "752". if the user enters the letter "v", txtTemp will be "752", and the new value for txtBox.Text will be "752v", and in the textChange event we will reset the value to the previous value (for example, "752"). this is done using the keydown event.
but what if the user did not type the letter "v", but he copied it from another place and used the paste function and then the new value txtBox.Text = "752v", but txtTemp will be "75" because keYDown was not even launched to commit the last txtBox value: (
it is here that the value of the "insert" textBox appears.
so step 5 in my pseudo code:
5- in the txtBox.paste event txtBox.paste make sure that you cancel this event by making e.Handled=true;
and now I go to the code:
//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; }
:)