I wanted to make a simple application for Windows Phone 7 that required a number of TextBox controls to only accept numeric input. Some would be able to take decimals, and others would not.
Sounds easy correct? It really isn’t as straight-forward as I would want it to be, or as easy as it is in ASP or Windows Forms programming or WPF.
The reason it is not as easy you think it would be is that the framework for Windows Phone 7 does not, at this time contain a way of the developers to distinguish between the special keys (the ones you get on a normal keyboard using the Shift key) and the numbers that would, on a normal keyboard, be under them. I think that, at some level, they are using the same code and passing a Shift key identifier to the control so that it knows what character to produce, but at the level we access it, there does not seem to be anyway to determine the use of that unseen Shift key.
What this does is that if you trap for the #, you will also trap and stop the entry of the number 3. This has caused developers some difficulty when trying to control the user entries.
There is a way to do it though. It is actually pretty easy, there are a few steps and I have demonstrated them below.
Step 1 – Choose the correct InputScope
The one that I found that worked the best was the Telephone InputScope. This one had all the digits and the least number of extra keys that we will have to block. It also does not have any button that would allow the user to go to another InputScope.
I made a simple method that I could then call once for each of the TextBox controls I wanted to restrict input to numbers only:
Then I called each one for the applicable TextBox controls:
Now when I run the application, and set focus to one of the text boxes, I get the numeric InputScope panel I want:
Step 2 – Handle Invalid Characters
The only problem with this InputScope is that there are a few invalid characters for a numeric control. The obvious ones are the “*“; “+” (hold the 0 key); “,” and the “#“. There are also some keys that are not obvious at first. These appear when you hold down the decimal “.” key:
You are then presented with four more keys that are invalid for a numeric TextBox: “(“; “)“; “x“; and “–“.
In order to trap and mask the TextBox control from these keys we need a method that will allow for the invalid characters to be removed. Since we already know about the PlatformKeyCode’s inability to distinguish between certain keys and their decimal equivalents, we have to do it on the KeyUp event instead of the KeyDown event.
We also have to take into account that for some fields we want to allow decimals, but for others, we want numbers only. In order to solve both problems with the least amount of code, we create a method that will be called by event handler methods:
Now, as mentioned before, we need to create handler methods to call this method that removes the invalid characters from the TextBox control:
Step 3 – Call the Code from the Controls
Now, all that is left is to set the handlers to the correct controls and we are done!
First, for controls that are NUMBERS ONLY, no decimals, the process is easy, simply call the appropriate event handler (in this case, numericOnlyTextBox_KeyUp) from the KeyUp event:
This will ensure that there are no decimals ever seen as the decimals are placed into the array holding the invalid characters and removed when found.
The only problem I found was that when I allowed decimals to be entered into the TextBox control, the user could add as many as they wanted. This made the numbers invalid and could cause errors in my code, so I had to create a method that would be called on the KeyDown event for TextBox controls that accepted decimals:
With TextBox controls that you want to allow a decimal in, you will have to call both this KeyDown event handler and a different KeyUp event handler:
Now, we have it! A quick and flexible way to handle numeric entry into TextBox controls.
Hope this helps,
Atley
Atley,
Thanks for the illustrating this. I was wondering how to force numbers on a TextBox and you answered my question.
The other question I have is how to get the SIP to show numbers rather than letters on the default keyboard when entering the TextBox. It would save the user an extra keystroke and some confusion when trying to type a number in a TextBox where they are expecting to enter a number (but instead they see letters by default). Is this possible?
Thanks,
Brent
Yes, you can have the SIP to show the number side of the default keyboard first by choosing the Digit InputScope. This will allow the user to still have access to the abcd key and therefore they can switch back to the letter side of the SIP.
If you want to only allow numbers in the control, you should use the Telephone InputScope as it does not offer the user the option of going back to a letter keyboard. This saves you from having to trap for all of the letters as well as a lot more special characters.
Awesome. Thanks for answering my question.
hello thanks for the article.
Thanks for that awesome posting. It saved MUCH time 🙂
Great!
Working great… Thank you so much
This was a excellent piece of writing. Your article is useful,thank you.
Nice post. Thank You for taking the time to share it with us.
Some small improvments:
* uses a foreach instead of for loop, simpler and faster 😉
* only allows the user to insert one decimal
Hope you like it:
private void MaskNumericInput(TextBox textBoxControl, bool allowDecimals)
{
string[] invalidChars = { “*”, “#”, “.”, “(“, “)”, “x”, “-“, “+”, ” “, “@” };
if(!allowDecimals)
{
invalidChars[invalidChars.Length – 1] = “,”;
}
foreach (string s in invalidChars)
{
textBoxControl.Text = textBoxControl.Text.Replace(s, “”);
}
int firstDotIndex = textBoxControl.Text.IndexOf(‘,’);
int lastDotIndex = textBoxControl.Text.LastIndexOf(‘,’);
if (firstDotIndex != lastDotIndex)
{
textBoxControl.Text = textBoxControl.Text.Remove(lastDotIndex);
}
textBoxControl.SelectionStart = textBoxControl.Text.Length;
}
Yes, it can definitely be done that way as well. Thanks!
@Richard – You would not want to use a foreach to do iterative processes on the phone. The Call to GetEnumorator() which the foreach loop does internally yields a slower performance over using the for statement.
If you start using a foreach, people will start talking about using Linq which opens open another large ball of wax around Garbage Collection.
You will want to consider performance impacts when creating your phone applications as it will directly relate to your customer satisfaction when they use the application you have built.
@Cory Thanks for pointing that out! Great point!
This is the modification of the above code that define the valid symbols in opposite to the above version that defines the invalid characters. Might suit better in some cases. The code below allows to enter only 0 or 1 and can be modified to include more valid characters in the if condition brackets.
for (int i = 0; i < textBoxControl.Text.Length; i++)
{
if (!textBoxControl.Text[i].Equals('0') && !textBoxControl.Text[i].Equals('1'))
{
textBoxControl.Text = textBoxControl.Text.Remove(i);
}
}
It is one way to do it, but I think that for the purposes of this situation, the multiple if statement would be a bit too verbose.
Very well done. Thanks for writing this!
What if someone from a different country tries to use it which has for example , instead of . ? It sounds like this works “only” one way and I can’t use a Globalization that easy?
That is a good point… I will look at changing the base methods to include globalization.
Thanks for the suggestion!!!
I need to add this to the code to use the Telephone Keyboard for each TextBox, right?
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
SetControls();
}
Btw. isn’t there something better to use Numbers than the Telephone Keyboard? 🙂
I wonder why I can use .Numbers but then it shows it not as intended like with the Telephone Keys…
Could you maybe also attach the Source for this example?
Thanks for this 🙂
You do block the second decimal point in the KeyDown event, why don’t you just also block all invalid characters there instead of removing them from the input in the KeyUp? I’m not a w7p developer, so there might be some non-obvious problem. Just curious.
Use new InputScope “Digits” and sjekk only for ” ” and “.” as illegal
Just simply add InputScope=”TelephoneNumber” to your xaml file
You will still have to deal with the extra characters that are allowed from that InputScope. It would slightly change the code needed.
Awesome, thanks for the learning experience.
private void SetInputScope(TextBox textBoxControl)
{
InputScopeNameValue digitsInputNameValue = InputScopeNameValue.Digits;
textBoxControl.InputScope = new InputScope()
{
Names = {new InputScopeName() {NameValue = digitsInputNameValue }}
};
}
Here the method i used is same, just slight modification, Instead of InputScopeNameValue.TelephoneNumber i have used Digits, by which only digits will display which will allow decimal values to be entered. Hope it helps.
Raship,
Digits and TelephoneNumber currently bring up the same SIP, so both are valid choices.
Hi,
I was reading your article and I would like to appreciate you for making it very simple and understandable. This article gives me a basic idea of TextBox control in widows phone development.
Thanks for wonderful post it really helpful for beginner as well as developer.
great, this is just what i am looking for.
however is there a solution to prevent user from pasting invalid value into the textbox?
You could put a check for invalid values in the TextChanged event, but that would create too many checks. You would have to put a check on the LostFocus event of the TextBox in order to properly trap for pasted values. You would also want to ensure that this check would be performed on navigation to be certain that there was no chance of an invalid value slipping in.
hi, is there a way where we can replace the clear text with “*” similar to password?
thks
I use InputScope=”Number” throughout my project when I need numeric input. It’s easier to set up – the only non-decimal keys you need to handle are the comma and the hyphen – and is less cluttered with unneeded keys.
Documented here (WP7): http://msdn.microsoft.com/en-us/library/system.windows.input.inputscopenamevalue(v=vs.95).aspx
(Haven’t had a chance to test it on WP8 yet but I assume it would work.)
Sorry for the late reply, yes, I use that too, but it didn’t exist in Windows Phone 7 when that article was written. I do agree that you can use that and slim down the code a little bit. Thanks for the feedback!