How to limit or prevent characters in a TextBox in C#? Or How to create a NumberTextBox or DigitBox object?
Let say you want to have a TextBox in which you only want to allow integers (0-9) or maybe you only want to allow strings, A-Za-z.
Well, lets play around with this for a second and see what we can do.
To get started do this:
- Create a new WPF Application project.
- In the designer, add a TextBox from the Toolbox.
- In the properties field for the TextBox click the icon that look like a lightening bolt to bring up events.
- Find the KeyDown event and double-click on it.
Ok, so you should now have the following function:
private void textBox1_KeyDown(object sender, KeyEventArgs e) { }
The key that was pressed is accessible from the KeyEventArgs variable, e. Specifically e.Key.
Key just happens to be an enum, which means they can basically be treated as integers.
The key press can be ignored by telling setting e.Handled=true. This way it is already marked as handled and will not be added to the TextBox.
Allow only number keys 0-9 in a TextBox
Here is a simple function to allow only natural numbers or number keys 0-9 in a TextBox. Be aware that the keys may be different in other languages.
private void textBox1_KeyDown(object sender, KeyEventArgs e) { if (e.Key < Key.D0 || e.Key > Key.D9) { e.Handled = true; } }
Wow, that was pretty simple, right? WRONG! It is not that easy.
You realize that there are two sets of numbers on a keyboard right? You have numbers in row above your QWERTY keys and you likely have a Number pad on the right of your keyboard as well. That is not all either.
What else did we forget, you might ask? Well, of the seven requirements we need to handle, we only handled one. For an application to be considered release quality or enterprise ready or stable, all seven of these should be handled.
- Numbers 1234567890 above QWERTY keys.
- Numpad numbers.
- You may want to allow pressing of the Delete, Backspace, and Tab keys.
- What about pasting?
- What about drag and drop?
- What about someone else calling your code and changing the text?
- Mnemonics should work.
Requirements
Here are the six requirements in clear statements.
- Allow pressing Numbers 1234567890 above QWERTY keys.
- Allow pressing Numpad numbers.
- Allow pressing of the Delete, Backspace, and Tab keys.
- Allow pasting so that only numbers in a string are added: A1B2C3 becomes 123.
- Allow drag and drop so that only numbers in a string are added: A1B2C3 becomes 123.
- Allow change in code at runtime so that only numbers in a string are added: A1B2C3 becomes 123.
- When another control has a mnemonic, such as Alt + S, pressing Alt + S, should property change the focus and place the cursor in the Alt + S control.
Remembering lists like this is something that comes with experience. If you thought of these on your own, good work. If you didn’t think of them on your own, don’t worry, experience comes with time.
So lets enhance this to handle each of these.
Handling both Number keys and Numpad keys
private void textBox1_KeyDown(object sender, KeyEventArgs e) { e.Handled = !IsNumberKey(e.Key); } private bool IsNumberKey(Key inKey) { if (inKey < Key.D0 || inKey > Key.D9) { if (inKey < Key.NumPad0 || inKey > Key.NumPad9) { return false; } } return true; }
All right, we now have two of the six requirements down.
Handling Delete, Backspace, and Tab, and Mnemonics
You can probably already guess how easy it will be to do something similar to handle these two keys.
protected void OnKeyDown(object sender, KeyEventArgs e) { e.Handled = !IsNumberKey(e.Key) && !IsActionKey(e.Key); } private bool IsNumberKey(Key inKey) { if (inKey < Key.D0 || inKey > Key.D9) { if (inKey < Key.NumPad0 || inKey > Key.NumPad9) { return false; } } return true; } private bool IsActionKey(Key inKey) { return inKey == Key.Delete || inKey == Key.Back || inKey == Key.Tab || inKey == Key.Return || Keyboard.Modifiers.HasFlag(ModifierKeys.Alt); }
Ok, now we have four of six requirements handled.
Handling Paste (Ctrl + V) and Drag and Drop
Yes, I can handle both at the same time with a new event TextChanged.
This is setup so that if someone pastes both letters and number, only the numbers are pasted: A1B2C3 becomes 123.
This event is not configured so we have to set it up.
- In the designer, click the TextBox.
- In the properties field for the TextBox click the icon that look like a lightening bolt to bring up events.
- Find the TextChanged event and double-click on it.
You should now have this stub code for the event function.
private void textBox1_TextChanged(object sender, TextChangedEventArgs e) { }
Here is some easy code to make sure each character is actually a digit.
protected void OnTextChanged(object sender, TextChangedEventArgs e) { base.Text = LeaveOnlyNumbers(Text); } private string LeaveOnlyNumbers(String inString) { String tmp = inString; foreach (char c in inString.ToCharArray()) { if (!IsDigit(c)) { tmp = tmp.Replace(c.ToString(), ""); } } return tmp; } public bool IsDigit(char c) { return (c >= '0' && c <= '9'); }
Guess what else? This last function actual handles the first five requirements all by itself. But it is less efficient so we will leave the previous requirements as they are.
Handling Direct Code Change
Ok, so some somehow your TextBox is passed inside code during runtime a string that contains more than just numbers. How are you going to handle it.
This is setup so that if someone pastes both letters and number, only the numbers are pasted: A1B2C3 becomes 123. Well, we need to run the same function as for Drag and Drop, so to not duplicate code, it is time to create a class or object.
Creating a NumberTextBox object
Now we need to make our code reusable. Lets create a class called NumberTextBox and it can do everything automagically.
NumberTextBox
using System; using System.Windows.Controls; using System.Windows.Input; namespace System.Windows.Controls { public class DigitBox : TextBox { #region Constructors /// <summary> /// The default constructor /// </summary> public DigitBox() { TextChanged += new TextChangedEventHandler(OnTextChanged); KeyDown += new KeyEventHandler(OnKeyDown); } #endregion #region Properties new public String Text { get { return base.Text; } set { base.Text = LeaveOnlyNumbers(value); } } #endregion #region Functions private bool IsNumberKey(Key inKey) { if (inKey < Key.D0 || inKey > Key.D9) { if (inKey < Key.NumPad0 || inKey > Key.NumPad9) { return false; } } return true; } private bool IsActionKey(Key inKey) { return inKey == Key.Delete || inKey == Key.Back || inKey == Key.Tab || inKey == Key.Return || Keyboard.Modifiers.HasFlag(ModifierKeys.Alt); } private string LeaveOnlyNumbers(String inString) { String tmp = inString; foreach (char c in inString.ToCharArray()) { if (!IsDigit(c)) { tmp = tmp.Replace(c.ToString(), ""); } } return tmp; } public bool IsDigit(char c) { return (c >= '0' && c <= '9'); } #endregion #region Event Functions protected void OnKeyDown(object sender, KeyEventArgs e) { e.Handled = !IsNumberKey(e.Key) && !IsActionKey(e.Key); } protected void OnTextChanged(object sender, TextChangedEventArgs e) { base.Text = LeaveOnlyNumbers(Text); } #endregion } }
Now I can delete the events and functions from the Window1.xaml.cs file. I don’t have to add any code to the Window1.xaml.cs. Instead I need to reference my local namespace in the Window1.xaml and then change the TextBox to a local:NumberTextBox. Here is the XAML.
<Window x:Class="TextBoxIntsOnly.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:TextBoxIntsOnly" Title="Window1" Height="300" Width="300"> <Grid> <local:DigitBox Margin="87,27,71,0" VerticalAlignment="Top" x:Name="textBox1" /> <Label Height="28" HorizontalAlignment="Left" Margin="9,25,0,0" Name="label1" VerticalAlignment="Top" Width="72">Integers:</Label> <TextBox Height="23" Margin="87,56,71,0" Name="textBox2" VerticalAlignment="Top" /> <Label Height="28" HorizontalAlignment="Left" Margin="9,54,0,0" Name="label2" VerticalAlignment="Top" Width="72">Alphabet:</Label> </Grid> </Window>
And now all seven requirements are met.
This site definitely has all the info I wanted about
this subject and didn?t know who to ask.
Top.Meinsparblog.de
How to limit or prevent characters in a TextBox in C#? Or How to create a NumberTextBox or DigitBox object? | Rhyous
best email marketing Aweber
How to limit or prevent characters in a TextBox in C#? Or How to create a NumberTextBox or DigitBox object? | Rhyous
adoption of Ecommerce online shopping in malaysia
How to limit or prevent characters in a TextBox in C#? Or How to create a NumberTextBox or DigitBox object? | Rhyous
family dentist in West Los Angeles
How to limit or prevent characters in a TextBox in C#? Or How to create a NumberTextBox or DigitBox object? | Rhyous
hey I followed this example using winforms masktextbox and realized that I can still delete characters and when I type a invalid character it enters one empty space.
can you explain why thanks.
I would like to know as well.
it should not delete characters but shift the cursor back on character.
lol I replies to my own comment! 😛
A BIG Thankyou!
Hello,
How to take 1 byte Hex input from a user in vb.net ? also does vb.net support direct Exclusive-OR (^)....
Thanks
is there a way to allow only numbers and prevent copy and paste?
no, this is not possible. only text works with copy and paste because numbers can't be copied. BUURRRRRRRP!
Thanks for such a nice piece of code. I can say today i learnt some validatin techniques.
Hi
This article has been really helpful to me but I also noticed that in the IsDigit, you needed to make it a logical AND not OR which someone else pointed out in the comments. The code in the article above still needs to be changed tho.
Thanks so much for this! Helped heaps.
Thanks for finding that bug.
I really like what you have done here. Two things:
In the final bit of code, why not just override the OnKeyDown and OnKeyChanged methods of the TextBox? Or is
Second, what code license is this code under? I cannot use it in our commercial app unless it is under some compatible license such as MIT, BSD, CPOL, Apache license, MS-PL, etc.
Oh, right. Most my code is under a BSD License unless otherwise specified. I added a license page stating such:
https://www.rhyous.com/programming-development/code-licensing/
Ok, thanks! Also, if you have the time (don't worry about it otherwise), I would be interested to know if there was a reason for subscribing directly to the KeyDown/TextChanged events rather than overriding the OnKeyDown and OnTextChanged handlers in the DigitBox class.
There was not thought put into that really. I wish I could say there was. It probably happened that way because my first attempt to do this was as an attached property to TextBox that subscribed to the events.
And what if i want to allow numbers and + - * / chars?
Such as for a calculator? I would create a third method called IsOperatorKey() and then change to use the next line:
e.Handled = !IsNumberKey(e.Key) && !IsActionKey(e.Key) && !IsOperatorKey()
Then add a method IsOperatorCharacter. Then edit this line too:
return (c >= '0' || c <= '9') || IsOperatorCharacter(c); Or at this point, I may create a similar object with a list or table of keys and a list of table of characters and then just call it a LimitedTextBox but you actually have to pass in the list of allowed keys and allowed characters.
Hi!
What is the advantages of this compared to:
private void TextBox1_TextChanged(object sender, EventArgs e)
{
TextBox1.Text = Regex.Replace(TextBox1.Text, "[^0-9]", "", RegexOptions.Compiled);
}
I know the regex isn't perhaps the most efficient, but all that code.
You got one reason right on. There was a goal of ultimate efficiency and Regex is not very efficient. However, if that were the only reason, it would not have been enough.
The other reason is that we needed the Text value to NOT change. See, while your method works, it also has a much more serious problem. It allows the Text value of the TextBox to change and then removes the change. You created two changes. Now assume you have code that runs when the Text changes. This code will run twice your way. It won't run at all my way. This object prevents the change on the key press.
Unfortunately there are other ways to change the value, and in those situations we use a method similar to yours, just without the regex.
Hi there,
nice code, but how do i implement this in my wpf-application, into the xaml??? I dont get it.
The part which describes that is missing... can jou add it please?
And in the last complete code snippet are a few syntaxy error, j2iu.
Best regards
Add the class to your project. Let's say you add it to namespame MyProject.Controls.
At the top of your XAML add this:
xmlns:ctrls="clr-namespace:MyProject.Controls;"
or if it is in an assembly:
xmlns:ctrls="clr-namespace:MyProject.Controls;assembly=MyProject"
The you use it as follows.
Hello again,
thanks for your help. I already had this.
Now I realized, that I have to write the attribute Name with an 'x:' before (the namespace in my case is the same as all other classes use in that project):
sry, I dont get the brakets..
what I meant is:
ctrls:DigitBox x:Name="YourName" /
I'll should get around to writing a post on using this, for simplicity's sake.
[...] https://www.rhyous.com/2010/06/18/how-to-limit-or-prevent-characters-in-a-textbox-in-csharp/ [...]
Hi Rhyous
your code simply works great thanks for it 🙂
But i dont know why i am getting error "Partial declarations of 'WpfApplication4.MainWindow' must not specify different base classes"
whats wrong ?
I think there is a bug where a keyboard shortcut or mnemonic cannot be used because Alt + Key is not allowed.
Alt + now works with this latest update!
My first idea was to rely on final text and avoid getting into details of how that text could have appeared. There is also text copy/paste.
I would do it the following way.
1. Get current text
2. Convert.ToInt get the number and check if it is within limit
3. If no, already bad
4. If yes, check if int.ToString == original text
Good idea. I believe I did cover copy and paste.
I also wondered if for efficiency's sake, if it was faster to compare each character than to do the regular expression.
private bool IsDigit(char c)
{
return c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || c == '6' || c == '7' || c == '8' || c == '9';
}
Then do a for loop to check each character.
I wish there was a way to highlight my lines of code and it would tell me how many lines of machine code the lines of code would create.
Sometimes the ideas are so simple, that I feel silly that someone else has to mention them to me.
Thanks Moody.
Should be
Thanks...I noticed a few other problems, a couple caused by WordPress or plugins (such as my XAML missing) and fixed them too.
The char type already has an IsDigit static method.
Thanks for the great example.
I really think however that something this commonly needed should be implimented as a Control as a part of the .net toolset.
But my grunting aside, thanks again 🙂
Xavier.
Hi Sr!
I write code for Handling Paste (Ctrl + V) as you mension above.
But i have an error that is i cannot write any character in that textbox.
Please solve my problem..
Thank for ur kindness...........
You mean you cannot type digits? Or you cannot type characters?
Put the debugger on line 34. Press a number and see what inKey variable is set to.
Works a treat! Really nice solid code. Cheers!