Bad detection of my keyboard(C#) - c#

Why when i click for example "a" on my keyboard program seems bad key "F8".
Diffrent examples:
"1" = "NumPad7"
"A" = "V"
"B" = "W"
Problem is in:
label.Content = (Key)key;
When i change (Key) for (char) it works but only for a-z and A-Z keys. How can i properly detect my keyboard?
public void Window_KeyDown(object sender, KeyEventArgs e)
{
if (condition == true)
{
int key;
int keyState;
for (key = 0; key < 127; key++)
{
keyState = GetAsyncKeyState(key);
if (keyState == 1 || keyState == -32767)
{
if(Keyboard.IsKeyDown(Key.LeftShift) ||
Keyboard.IsKeyDown(Key.RightShift ))
{
Save_With_Big_Letters(key);
label.Content = (Key)key;
}
else
{
Save_With_Small_Letters(key);
label.Content = (Key)(key + 32);
}
}
}
}
}

GetAsyncKeyState uses the older, WindowsForms key values. To make this work, either use System.Windows.Forms.Keys enum, or just use the KeyEventArgs.Key value.
Like this:
label.Content = (System.Windows.Forms.Keys)key;
or the better way:
label.Content = e.Key;

Related

Suppress Key "Bing" with KeyPressEvent?

Within our application, there is a usercontrol, which allows to enter a number (inside a numericupdown) followed by a combobox which allows to select the SI-Prefix ([p, n, µ, m, -, k, M, G, T] small to big)
Now, for easier usage, I thought it would be nice to capture the KeyPress-Event on the numericUpDown and set the combobox accordingly. (If m is pressed, select mili (m), if G is pressed, select Giga (G))
This works flawless with the following handler / selector:
private void numericUpDown1_KeyPress(object sender, KeyPressEventArgs e)
{
if (char.IsLetter(e.KeyChar))
{
//Check, if its valid for si prefixes.
if (this.siSelector1.TrySelect(e.KeyChar)
{
e.Handled = true;
}
}
}
Where TrySelect does nothing but the following:
public Boolean TrySelect(Char chr)
{
var entry = this.comboBox_siPrefix.Items.Cast<KeyValuePair<String,Double>>().Where(e => e.Key.Contains("(" + chr + ")")).FirstOrDefault();
if (!entry.Equals(new KeyValuePair<String, Double>()))
{
this.comboBox_siPrefix.SelectedItem = entry;
return true;
}
return false;
}
That's fine, but everytime the user hears a "BING" whenever a non-numeric Key is pressed on the numericupdown.
I read about e.SuppressKeyPress, which unfortunately isn't available with KeyPressEventArgs - it's only available for KeyEventArgs.
So, trying the whole thing with the KeyDown-Event works. (No "BING") - but I wasn't able to capture capital keys, as every KeyDown will fire the Event immediately...
private void numericUpDown1_KeyDown(object sender, KeyEventArgs e)
{
KeysConverter kc = new KeysConverter();
if (char.IsLetter(kc.ConvertToString(e.KeyCode)[0]))
{
//Check, if its valid for si prefixes.
if (this.siSelector1.TrySelect(kc.ConvertToString(e.KeyCode)[0]))
{
e.Handled = true;
e.SuppressKeyPress = true;
}
}
}
Any Ideas?
Figured out a way:
When Using KeyDown-Event, you can use e.Modifiers to check, if another key is down'd at the same time.
I dunno why, but for the KeyDown-Event e.KeyValue as well as e.KeyCode always return the CAPITAL version of the key.
So, I modified the handler to convert every char to lower-case, and only convert it to upper-Case if SHIFT is pressed at the same time:
Works - no "BING" (for valid SI-Prefixes). :-)
private void numericUpDown1_KeyDown(object sender, KeyEventArgs e)
{
KeysConverter kc = new KeysConverter();
char c = char.ToLower(kc.ConvertToString(e.KeyValue)[0]);
if (char.IsLetter(c))
{
//Caps?
if (e.Modifiers == Keys.Shift)
{
c = char.ToUpper(c);
}
//Check, if its valid for si prefixes.
if (this.siSelector1.TrySelect(c))
{
e.Handled = true;
e.SuppressKeyPress = true;
}
}
}
The above solution does not apply for µ (CTRL+ALT+m or ALT GR+m)
Update: This is not 100%, but I didn't get it by now:
IF the ALT-Key is pressed, The Char-Code always reports a "M".
Update 2:
So, I had to exclude the "m" from beeing matched with char.isLetter() (if alt is pressed) and finally add another check.
I found, that comparing e.KeyValue==77 worked as expected, while comparing c=='m' didn't... (then µ was inserted into the numericupdown, which it shouldn't)
if (ctrl && alt && c=='m'):
if (ctrl && alt && e.KeyValue==77)
Dunno why - Ideas?
private void numericUpDown1_KeyDown(object sender, KeyEventArgs e)
{
KeysConverter kc = new KeysConverter();
char c = char.ToLower(kc.ConvertToString(e.KeyValue)[0]);
Boolean ctrl = e.Control;
Boolean alt = e.Alt;
Boolean shift = e.Shift;
int keyPadStart = (int)Keys.NumPad0;
int keyPadEnd = (int)Keys.NumPad9;
if (e.KeyValue >= keyPadStart && e.KeyValue <= keyPadEnd)
{
//send to numeric updown.
return;
}
if (char.IsLetter(c) && !alt)
{
if (shift) c = char.ToUpper(c);
//Check, if its valid for si prefixes.
if (this.siSelector1.TrySelect(c))
{
e.Handled = true;
e.SuppressKeyPress = true;
}
}
//not working: if (ctrl && alt && c=='m')
if (ctrl && alt && e.KeyValue==77)
{
//Check, if its valid for si prefixes.
if (this.siSelector1.TrySelect('µ'))
{
e.Handled = true;
e.SuppressKeyPress = true;
}
}
}

Can't We get Current value of Text Box in PreviewKeyDown Event?

I am trying to read Current value of Text Box in PreviewKeyDown Event but unable to get current value.
Here is my code ,
private void txtDoscountValue_PreviewKeyDown(object sender, KeyEventArgs e)
{
try
{
if (txtDoscountValue.Text == string.Empty)
discountPercentage = 0;
else
discountPercentage = float.Parse(txtDoscountValue.Text);
CalculateCart(cartItems, discountPercentage, 0);
}
catch
{ }
}
Maybe your problem is that you are asking at PreviewKeyDown, so when it gets called, there is still no values in the box. If you want to get called when the box actually changes you need to hook to KeyDown or even better TextChanged.
PreviewKeyDown is for checking the content of the change before actually applying it, which is kind of validation.
The value of the modification is stored in the keyEventArgs, not in the textbox.
It is possible to read value of TextBox at any time with Text property of TextBox control:
var currentValue=textBox.Text;
To read inputted keys of keyboard, you can use e.Key of KeyEventArgs:
private void txtDoscountValue_PreviewKeyDown(object sender, KeyEventArgs e)
{
try
{
string input=e.Key;
var ee = txtDoscountValue.Text;
}
catch { }
}
Update:
It is possible to use KeyConverter class to convert Keys to string. You should add reference to assembly System.Windows.Forms to your WPF project to use KeyConverter class:
private void textBox1_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
try
{
char c = '\0';
System.Windows.Input.Key key = e.Key;
if ((key >= Key.A) && (key <= Key.Z))
{
c = (char)((int)'a' + (int)(key - Key.A));
}
else if ((key >= Key.D0) && (key <= Key.D9))
{
c = (char)((int)'0' + (int)(key - Key.D0));
}
else if ((key >= Key.NumPad0) && (key <= Key.NumPad9))
{
c = (char)((int)'0' + (int)(key - Key.NumPad0));
}
//here your logic
}
catch { }
}
}

How to prohibit write letters in a textbox? C# [duplicate]

I have a windows forms app with a textbox control that I want to only accept integer values. In the past I've done this kind of validation by overloading the KeyPress event and just removing characters which didn't fit the specification. I've looked at the MaskedTextBox control but I'd like a more general solution that could work with perhaps a regular expression, or depend on the values of other controls.
Ideally this would behave such that pressing a non numeric character would either produce no result or immediately provide the user with feedback about the invalid character.
Two options:
Use a NumericUpDown instead. NumericUpDown does the filtering for you, which is nice. Of course it also gives your users the ability to hit the up and down arrows on the keyboard to increment and decrement the current value.
Handle the appropriate keyboard events to prevent anything but numeric input. I've had success with this two event handlers on a standard TextBox:
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) &&
(e.KeyChar != '.'))
{
e.Handled = true;
}
// only allow one decimal point
if ((e.KeyChar == '.') && ((sender as TextBox).Text.IndexOf('.') > -1))
{
e.Handled = true;
}
}
You can remove the check for '.' (and the subsequent check for more than one '.') if your TextBox shouldn't allow decimal places. You could also add a check for '-' if your TextBox should allow negative values.
If you want to limit the user for number of digit, use: textBox1.MaxLength = 2; // this will allow the user to enter only 2 digits
And just because it's always more fun to do stuff in one line...
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = !char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar);
}
NOTE: This DOES NOT prevent a user from Copy / Paste into this textbox. It's not a fail safe way to sanitize your data.
I am assuming from context and the tags you used that you are writing a .NET C# app. In this case, you can subscribe to the text changed event, and validate each key stroke.
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (System.Text.RegularExpressions.Regex.IsMatch(textBox1.Text, "[^0-9]"))
{
MessageBox.Show("Please enter only numbers.");
textBox1.Text = textBox1.Text.Remove(textBox1.Text.Length - 1);
}
}
Here is a simple standalone Winforms custom control, derived from the standard TextBox, that allows only System.Int32 input (it could be easily adapted for other types such as System.Int64, etc.). It supports copy/paste operations and negative numbers:
public class Int32TextBox : TextBox
{
protected override void OnKeyPress(KeyPressEventArgs e)
{
base.OnKeyPress(e);
NumberFormatInfo fi = CultureInfo.CurrentCulture.NumberFormat;
string c = e.KeyChar.ToString();
if (char.IsDigit(c, 0))
return;
if ((SelectionStart == 0) && (c.Equals(fi.NegativeSign)))
return;
// copy/paste
if ((((int)e.KeyChar == 22) || ((int)e.KeyChar == 3))
&& ((ModifierKeys & Keys.Control) == Keys.Control))
return;
if (e.KeyChar == '\b')
return;
e.Handled = true;
}
protected override void WndProc(ref System.Windows.Forms.Message m)
{
const int WM_PASTE = 0x0302;
if (m.Msg == WM_PASTE)
{
string text = Clipboard.GetText();
if (string.IsNullOrEmpty(text))
return;
if ((text.IndexOf('+') >= 0) && (SelectionStart != 0))
return;
int i;
if (!int.TryParse(text, out i)) // change this for other integer types
return;
if ((i < 0) && (SelectionStart != 0))
return;
}
base.WndProc(ref m);
}
Update 2017: My first answer has some issues:
you can type something that's longer than an integer of a given type (for example 2147483648 is greater than Int32.MaxValue);
more generally, there's no real validation of the result of what has been typed;
it only handles int32, you'll have to write specific TextBox derivated control for each type (Int64, etc.)
So I came up with another version that's more generic, that still supports copy/paste, + and - sign, etc.
public class ValidatingTextBox : TextBox
{
private string _validText;
private int _selectionStart;
private int _selectionEnd;
private bool _dontProcessMessages;
public event EventHandler<TextValidatingEventArgs> TextValidating;
protected virtual void OnTextValidating(object sender, TextValidatingEventArgs e) => TextValidating?.Invoke(sender, e);
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (_dontProcessMessages)
return;
const int WM_KEYDOWN = 0x100;
const int WM_ENTERIDLE = 0x121;
const int VK_DELETE = 0x2e;
bool delete = m.Msg == WM_KEYDOWN && (int)m.WParam == VK_DELETE;
if ((m.Msg == WM_KEYDOWN && !delete) || m.Msg == WM_ENTERIDLE)
{
DontProcessMessage(() =>
{
_validText = Text;
_selectionStart = SelectionStart;
_selectionEnd = SelectionLength;
});
}
const int WM_CHAR = 0x102;
const int WM_PASTE = 0x302;
if (m.Msg == WM_CHAR || m.Msg == WM_PASTE || delete)
{
string newText = null;
DontProcessMessage(() =>
{
newText = Text;
});
var e = new TextValidatingEventArgs(newText);
OnTextValidating(this, e);
if (e.Cancel)
{
DontProcessMessage(() =>
{
Text = _validText;
SelectionStart = _selectionStart;
SelectionLength = _selectionEnd;
});
}
}
}
private void DontProcessMessage(Action action)
{
_dontProcessMessages = true;
try
{
action();
}
finally
{
_dontProcessMessages = false;
}
}
}
public class TextValidatingEventArgs : CancelEventArgs
{
public TextValidatingEventArgs(string newText) => NewText = newText;
public string NewText { get; }
}
For Int32, you can either derive from it, like this:
public class Int32TextBox : ValidatingTextBox
{
protected override void OnTextValidating(object sender, TextValidatingEventArgs e)
{
e.Cancel = !int.TryParse(e.NewText, out int i);
}
}
or w/o derivation, use the new TextValidating event like this:
var vtb = new ValidatingTextBox();
...
vtb.TextValidating += (sender, e) => e.Cancel = !int.TryParse(e.NewText, out int i);
but what's nice is it works with any string, and any validation routine.
This is exactly what the Validated/Validating events were designed for.
Here's the MSDN article on the topic: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.validating.aspx
The TL;DR version: check the .Text property in the Validating event and set e.Cancel=True when the data is invalid.
When you set e.Cancel=True, the user can't leave the field, but you will need to give them some kind of feedback that something's wrong. I change the box's background color to light red to indicate a problem. Make sure to set it back to SystemColors.Window when Validating is called with a good value.
Try a MaskedTextBox. It takes a simple mask format so you can limit the input to numbers or dates or whatever.
You can use the TextChanged event
private void textBox_BiggerThan_TextChanged(object sender, EventArgs e)
{
long a;
if (! long.TryParse(textBox_BiggerThan.Text, out a))
{
// If not int clear textbox text or Undo() last operation
textBox_LessThan.Clear();
}
}
This might be useful. It allows "real" numeric values, including proper decimal points and preceding plus or minus signs. Call it from within the related KeyPress event.
private bool IsOKForDecimalTextBox(char theCharacter, TextBox theTextBox)
{
// Only allow control characters, digits, plus and minus signs.
// Only allow ONE plus sign.
// Only allow ONE minus sign.
// Only allow the plus or minus sign as the FIRST character.
// Only allow ONE decimal point.
// Do NOT allow decimal point or digits BEFORE any plus or minus sign.
if (
!char.IsControl(theCharacter)
&& !char.IsDigit(theCharacter)
&& (theCharacter != '.')
&& (theCharacter != '-')
&& (theCharacter != '+')
)
{
// Then it is NOT a character we want allowed in the text box.
return false;
}
// Only allow one decimal point.
if (theCharacter == '.'
&& theTextBox.Text.IndexOf('.') > -1)
{
// Then there is already a decimal point in the text box.
return false;
}
// Only allow one minus sign.
if (theCharacter == '-'
&& theTextBox.Text.IndexOf('-') > -1)
{
// Then there is already a minus sign in the text box.
return false;
}
// Only allow one plus sign.
if (theCharacter == '+'
&& theTextBox.Text.IndexOf('+') > -1)
{
// Then there is already a plus sign in the text box.
return false;
}
// Only allow one plus sign OR minus sign, but not both.
if (
(
(theCharacter == '-')
|| (theCharacter == '+')
)
&&
(
(theTextBox.Text.IndexOf('-') > -1)
||
(theTextBox.Text.IndexOf('+') > -1)
)
)
{
// Then the user is trying to enter a plus or minus sign and
// there is ALREADY a plus or minus sign in the text box.
return false;
}
// Only allow a minus or plus sign at the first character position.
if (
(
(theCharacter == '-')
|| (theCharacter == '+')
)
&& theTextBox.SelectionStart != 0
)
{
// Then the user is trying to enter a minus or plus sign at some position
// OTHER than the first character position in the text box.
return false;
}
// Only allow digits and decimal point AFTER any existing plus or minus sign
if (
(
// Is digit or decimal point
char.IsDigit(theCharacter)
||
(theCharacter == '.')
)
&&
(
// A plus or minus sign EXISTS
(theTextBox.Text.IndexOf('-') > -1)
||
(theTextBox.Text.IndexOf('+') > -1)
)
&&
// Attempting to put the character at the beginning of the field.
theTextBox.SelectionStart == 0
)
{
// Then the user is trying to enter a digit or decimal point in front of a minus or plus sign.
return false;
}
// Otherwise the character is perfectly fine for a decimal value and the character
// may indeed be placed at the current insertion position.
return true;
}
Just use a NumericUpDown control and set those ugly up down buttons visibility to false.
numericUpDown1.Controls[0].Visible = false;
NumericUpDown is actually a collection of controls containing a 'spin box' (up down buttons), a text box and some code to validate and wange-jangle it all together.
Marking:
YourNumericUpDown.Controls[0].visible = false
will hide the buttons while keeping the underlying code active.
While not being an obvious solution it is simple and effective. .Controls[1] would hide the text box portion if you wanted to do that instead.
I've been working on a collection of components to complete missing stuff in WinForms, here it is: Advanced Forms
In particular this is the class for a Regex TextBox
/// <summary>Represents a Windows text box control that only allows input that matches a regular expression.</summary>
public class RegexTextBox : TextBox
{
[NonSerialized]
string lastText;
/// <summary>A regular expression governing the input allowed in this text field.</summary>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public virtual Regex Regex { get; set; }
/// <summary>A regular expression governing the input allowed in this text field.</summary>
[DefaultValue(null)]
[Category("Behavior")]
[Description("Sets the regular expression governing the input allowed for this control.")]
public virtual string RegexString {
get {
return Regex == null ? string.Empty : Regex.ToString();
}
set {
if (string.IsNullOrEmpty(value))
Regex = null;
else
Regex = new Regex(value);
}
}
protected override void OnTextChanged(EventArgs e) {
if (Regex != null && !Regex.IsMatch(Text)) {
int pos = SelectionStart - Text.Length + (lastText ?? string.Empty).Length;
Text = lastText;
SelectionStart = Math.Max(0, pos);
}
lastText = Text;
base.OnTextChanged(e);
}
}
Simply adding something like myNumbericTextBox.RegexString = "^(\\d+|)$"; should suffice.
simply use this code in textbox :
private void textBox1_TextChanged(object sender, EventArgs e)
{
double parsedValue;
if (!double.TryParse(textBox1.Text, out parsedValue))
{
textBox1.Text = "";
}
}
Both integers and floats need to be accepted, including the negative numbers.
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
// Text
string text = ((Control) sender).Text;
// Is Negative Number?
if (e.KeyChar == '-' && text.Length == 0)
{
e.Handled = false;
return;
}
// Is Float Number?
if (e.KeyChar == '.' && text.Length > 0 && !text.Contains("."))
{
e.Handled = false;
return;
}
// Is Digit?
e.Handled = (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar));
}
I have made something for this on CodePlex.
It works by intercepting the TextChanged event. If the result is a good number it will be stored. If it is something wrong, the last good value will be restored. The source is a bit too large to publish here, but here is a link to the class that handles the core of this logic.
In our webpage with the definition of textbox we can add an onkeypress event for accepting only numbers. It will not show any message but it will prevent you from wrong input. It worked for me, user could not enter anything except number.
<asp:TextBox runat="server" ID="txtFrom"
onkeypress="if(isNaN(String.fromCharCode(event.keyCode))) return false;">
This is my aproach:
using linq (easy to modify filter)
copy/paste proof code
keeps caret position when you press a forbidden character
accepts left zeroes
and any size numbers
private void numeroCuenta_TextChanged(object sender, EventArgs e)
{
string org = numeroCuenta.Text;
string formated = string.Concat(org.Where(c => (c >= '0' && c <= '9')));
if (formated != org)
{
int s = numeroCuenta.SelectionStart;
if (s > 0 && formated.Length > s && org[s - 1] != formated[s - 1]) s--;
numeroCuenta.Text = formated;
numeroCuenta.SelectionStart = s;
}
}
This is a nice and short way to do it with .NET 5/Core
private void textBox1_KeyDown(object sender, KeyEventArgs e) {
if (e.KeyData != Keys.Back)
e.SuppressKeyPress = !int.TryParse(Convert.ToString((char) e.KeyData), out int _);
}
Edit: Added support for backspace key
you could use TextChanged/ Keypress event, use a regex to filter on numbers and take some action.
I would handle it in the KeyDown event.
void TextBox_KeyDown(object sender, KeyEventArgs e)
{
char c = Convert.ToChar(e.PlatformKeyCode);
if (!char.IsDigit(c))
{
e.Handled = true;
}
}
private void txt3_KeyPress(object sender, KeyPressEventArgs e)
{
for (int h = 58; h <= 127; h++)
{
if (e.KeyChar == h) //58 to 127 is alphabets tat will be blocked
{
e.Handled = true;
}
}
for(int k=32;k<=47;k++)
{
if (e.KeyChar == k) //32 to 47 are special characters tat will
{ be blocked
e.Handled = true;
}
}
}
try this is very simple
Take a look at Input handling in WinForm
I have posted my solution which uses the ProcessCmdKey and OnKeyPress events on the textbox. The comments show you how to use a Regex to verify the keypress and block/allow appropriately.
Hi you can do something like this in the textchanged event of the textbox.
here is a demo
private void textBox1_TextChanged(object sender, EventArgs e)
{
string actualdata = string.Empty;
char[] entereddata = textBox1.Text.ToCharArray();
foreach (char aChar in entereddata.AsEnumerable())
{
if (Char.IsDigit(aChar))
{
actualdata = actualdata + aChar;
// MessageBox.Show(aChar.ToString());
}
else
{
MessageBox.Show(aChar + " is not numeric");
actualdata.Replace(aChar, ' ');
actualdata.Trim();
}
}
textBox1.Text = actualdata;
}
It seems like many of the current answers to this question are manually parsing the input text. If you're looking for a specific built-in numeric type (e.g. int or double), why not just delegate the work to that type's TryParse method? For example:
public class IntTextBox : TextBox
{
string PreviousText = "";
int BackingResult;
public IntTextBox()
{
TextChanged += IntTextBox_TextChanged;
}
public bool HasResult { get; private set; }
public int Result
{
get
{
return HasResult ? BackingResult : default(int);
}
}
void IntTextBox_TextChanged(object sender, EventArgs e)
{
HasResult = int.TryParse(Text, out BackingResult);
if (HasResult || string.IsNullOrEmpty(Text))
{
// Commit
PreviousText = Text;
}
else
{
// Revert
var changeOffset = Text.Length - PreviousText.Length;
var previousSelectionStart =
Math.Max(0, SelectionStart - changeOffset);
Text = PreviousText;
SelectionStart = previousSelectionStart;
}
}
}
If you want something more generic but still compatible with Visual Studio's Designer:
public class ParsableTextBox : TextBox
{
TryParser BackingTryParse;
string PreviousText = "";
object BackingResult;
public ParsableTextBox()
: this(null)
{
}
public ParsableTextBox(TryParser tryParse)
{
TryParse = tryParse;
TextChanged += ParsableTextBox_TextChanged;
}
public delegate bool TryParser(string text, out object result);
public TryParser TryParse
{
set
{
Enabled = !(ReadOnly = value == null);
BackingTryParse = value;
}
}
public bool HasResult { get; private set; }
public object Result
{
get
{
return GetResult<object>();
}
}
public T GetResult<T>()
{
return HasResult ? (T)BackingResult : default(T);
}
void ParsableTextBox_TextChanged(object sender, EventArgs e)
{
if (BackingTryParse != null)
{
HasResult = BackingTryParse(Text, out BackingResult);
}
if (HasResult || string.IsNullOrEmpty(Text))
{
// Commit
PreviousText = Text;
}
else
{
// Revert
var changeOffset = Text.Length - PreviousText.Length;
var previousSelectionStart =
Math.Max(0, SelectionStart - changeOffset);
Text = PreviousText;
SelectionStart = previousSelectionStart;
}
}
}
And finally, if you want something fully generic and don't care about Designer support:
public class ParsableTextBox<T> : TextBox
{
TryParser BackingTryParse;
string PreviousText;
T BackingResult;
public ParsableTextBox()
: this(null)
{
}
public ParsableTextBox(TryParser tryParse)
{
TryParse = tryParse;
TextChanged += ParsableTextBox_TextChanged;
}
public delegate bool TryParser(string text, out T result);
public TryParser TryParse
{
set
{
Enabled = !(ReadOnly = value == null);
BackingTryParse = value;
}
}
public bool HasResult { get; private set; }
public T Result
{
get
{
return HasResult ? BackingResult : default(T);
}
}
void ParsableTextBox_TextChanged(object sender, EventArgs e)
{
if (BackingTryParse != null)
{
HasResult = BackingTryParse(Text, out BackingResult);
}
if (HasResult || string.IsNullOrEmpty(Text))
{
// Commit
PreviousText = Text;
}
else
{
// Revert
var changeOffset = Text.Length - PreviousText.Length;
var previousSelectionStart =
Math.Max(0, SelectionStart - changeOffset);
Text = PreviousText;
SelectionStart = previousSelectionStart;
}
}
}
Using the approach described in Fabio Iotti's answer I have created a more generic solution:
public abstract class ValidatedTextBox : TextBox {
private string m_lastText = string.Empty;
protected abstract bool IsValid(string text);
protected sealed override void OnTextChanged(EventArgs e) {
if (!IsValid(Text)) {
var pos = SelectionStart - Text.Length + m_lastText.Length;
Text = m_lastText;
SelectionStart = Math.Max(0, pos);
}
m_lastText = Text;
base.OnTextChanged(e);
}
}
"ValidatedTextBox", which contains all nontrivial validation behavior.
All that's left to do is inherit from this class and override "IsValid" method with whatever validation logic is required.
For example, using this class, it is possible to create "RegexedTextBox" which will accept only strings which match specific regular expression:
public abstract class RegexedTextBox : ValidatedTextBox {
private readonly Regex m_regex;
protected RegexedTextBox(string regExpString) {
m_regex = new Regex(regExpString);
}
protected override bool IsValid(string text) {
return m_regex.IsMatch(Text);
}
}
After that, inheriting from the "RegexedTextBox" class, we can easily create "PositiveNumberTextBox" and "PositiveFloatingPointNumberTextBox" controls:
public sealed class PositiveNumberTextBox : RegexedTextBox {
public PositiveNumberTextBox() : base(#"^\d*$") { }
}
public sealed class PositiveFloatingPointNumberTextBox : RegexedTextBox {
public PositiveFloatingPointNumberTextBox()
: base(#"^(\d+\" + CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator + #")?\d*$") { }
}
Sorry to wake the dead, but I thought someone might find this useful for future reference.
Here is how I handle it. It handles floating point numbers, but can easily be modified for integers.
Basically you can only press 0 - 9 and .
You can only have one 0 before the .
All other characters are ignored and the cursor position maintained.
private bool _myTextBoxChanging = false;
private void myTextBox_TextChanged(object sender, EventArgs e)
{
validateText(myTextBox);
}
private void validateText(TextBox box)
{
// stop multiple changes;
if (_myTextBoxChanging)
return;
_myTextBoxChanging = true;
string text = box.Text;
if (text == "")
return;
string validText = "";
bool hasPeriod = false;
int pos = box.SelectionStart;
for (int i = 0; i < text.Length; i++ )
{
bool badChar = false;
char s = text[i];
if (s == '.')
{
if (hasPeriod)
badChar = true;
else
hasPeriod = true;
}
else if (s < '0' || s > '9')
badChar = true;
if (!badChar)
validText += s;
else
{
if (i <= pos)
pos--;
}
}
// trim starting 00s
while (validText.Length >= 2 && validText[0] == '0')
{
if (validText[1] != '.')
{
validText = validText.Substring(1);
if (pos < 2)
pos--;
}
else
break;
}
if (pos > validText.Length)
pos = validText.Length;
box.Text = validText;
box.SelectionStart = pos;
_myTextBoxChanging = false;
}
Here is a quickly modified int version:
private void validateText(TextBox box)
{
// stop multiple changes;
if (_myTextBoxChanging)
return;
_myTextBoxChanging = true;
string text = box.Text;
if (text == "")
return;
string validText = "";
int pos = box.SelectionStart;
for (int i = 0; i < text.Length; i++ )
{
char s = text[i];
if (s < '0' || s > '9')
{
if (i <= pos)
pos--;
}
else
validText += s;
}
// trim starting 00s
while (validText.Length >= 2 && validText.StartsWith("00"))
{
validText = validText.Substring(1);
if (pos < 2)
pos--;
}
if (pos > validText.Length)
pos = validText.Length;
box.Text = validText;
box.SelectionStart = pos;
_myTextBoxChanging = false;
}
This one works with copy and paste, drag and drop, key down, prevents overflow and is pretty simple
public partial class IntegerBox : TextBox
{
public IntegerBox()
{
InitializeComponent();
this.Text = 0.ToString();
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
}
private String originalValue = 0.ToString();
private void Integerbox_KeyPress(object sender, KeyPressEventArgs e)
{
originalValue = this.Text;
}
private void Integerbox_TextChanged(object sender, EventArgs e)
{
try
{
if(String.IsNullOrWhiteSpace(this.Text))
{
this.Text = 0.ToString();
}
this.Text = Convert.ToInt64(this.Text.Trim()).ToString();
}
catch (System.OverflowException)
{
MessageBox.Show("Value entered is to large max value: " + Int64.MaxValue.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
this.Text = originalValue;
}
catch (System.FormatException)
{
this.Text = originalValue;
}
catch (System.Exception ex)
{
this.Text = originalValue;
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK , MessageBoxIcon.Error);
}
}
}
Do not forget that a user can paste an invalid text in a TextBox.
If you want to restrict that, follow the below code:
private void ultraTextEditor1_TextChanged(object sender, EventArgs e)
{
string append="";
foreach (char c in ultraTextEditor1.Text)
{
if ((!Char.IsNumber(c)) && (c != Convert.ToChar(Keys.Back)))
{
}
else
{
append += c;
}
}
ultraTextEditor1.Text = append;
}
I was also looking for the best way to check only numbers in textbox and problem with keypress was it does not support copy paste by right click or clipboard so came up with this code which validates the when cursor leaves the text field and also it checks for empty field. (adapted version of newguy)
private void txtFirstValue_MouseLeave(object sender, EventArgs e)
{
int num;
bool isNum = int.TryParse(txtFirstValue.Text.Trim(), out num);
if (!isNum && txtFirstValue.Text != String.Empty)
{
MessageBox.Show("The First Value You Entered Is Not a Number, Please Try Again", "Invalid Value Detected", MessageBoxButtons.OK, MessageBoxIcon.Error);
txtFirstValue.Clear();
}
}
Here are more than 30 answers and a lot of answers are helpful. But I want to share a generalized form for the System.Windows.Forms.TextBox and System.Windows.Controls.TextBox.
There is not available KeyPress event in System.Windows.Controls.TextBox.
This answer is for those people who want to implement with the same logic for System.Windows.Forms.TextBox and System.Windows.Controls.TextBox.
This is NumberTextBox code. Use commented line instead of the previous line for System.Windows.Controls.TextBox.
public class NumberTextBox : System.Windows.Forms.TextBox
//public class NumberTextBox : System.Windows.Controls.TextBox
{
private double _maxValue;
private double _minValue;
private bool _flag;
private string _previousValue;
public NumberTextBox()
{
this.TextAlign = HorizontalAlignment.Right;
//TextAlignment = TextAlignment.Right;
KeyDown += TextBox_KeyDown;
TextChanged += TextBox_TextChanged;
_minValue = double.MinValue;
_maxValue = double.MaxValue;
}
private void TextBox_KeyDown(object sender, KeyEventArgs e)
{
_previousValue = this.Text;
_flag = this.SelectedText.Length > 0;
}
private void TextBox_TextChanged(object sender, EventArgs e)
//private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var text = this.Text;
if (text.Length < 1) return;
var cursorPosition = SelectionStart == 0 ? SelectionStart : SelectionStart - 1;
var insertedChar = text[cursorPosition];
if (IsInvalidInput(insertedChar, cursorPosition, text))
{
HandleText(text, cursorPosition);
}
ValidateRange(text, cursorPosition);
}
private bool IsInvalidInput(char insertedChar, int cursorPosition, string text)
{
return !char.IsDigit(insertedChar) && insertedChar != '.' && insertedChar != '-' ||
insertedChar == '-' && cursorPosition != 0 ||
text.Count(x => x == '.') > 1 ||
text.Count(x => x == '-') > 1;
}
private void HandleText(string text, int cursorPosition)
{
this.Text = _flag ? _previousValue : text.Remove(cursorPosition, 1);
this.SelectionStart = cursorPosition;
this.SelectionLength = 0;
}
private void ValidateRange(string text, int cursorPosition)
{
try
{
if (text == "." || _minValue < 0 && text == "-") return;
var doubleValue = Convert.ToDouble(text);
if (doubleValue > _maxValue || doubleValue < _minValue)
{
HandleText(text, cursorPosition);
}
}
catch (Exception)
{
HandleText(text, cursorPosition);
}
}
protected void SetProperties(double minValue = double.MinValue, double maxValue = double.MaxValue)
{
_minValue = minValue;
_maxValue = maxValue;
}
}
PositiveNumberTextBox code:
public class PositiveNumberTextBox : NumberTextBox
{
public PositiveNumberTextBox()
{
SetProperties(0);
}
}
FractionNumberTextBox code:
public class FractionNumberTextBox : NumberTextBox
{
public FractionNumberTextBox()
{
SetProperties(0, 0.999999);
}
}
int Number;
bool isNumber;
isNumber = int32.TryPase(textbox1.text, out Number);
if (!isNumber)
{
(code if not an integer);
}
else
{
(code if an integer);
}
3 solution
1)
//Add to the textbox's KeyPress event
//using Regex for number only textBox
private void txtBox_KeyPress(object sender, KeyPressEventArgs e)
{
if (!System.Text.RegularExpressions.Regex.IsMatch(e.KeyChar.ToString(), "\\d+"))
e.Handled = true;
}
2)
an another solution from msdn
// Boolean flag used to determine when a character other than a number is entered.
private bool nonNumberEntered = false;
// Handle the KeyDown event to determine the type of character entered into the control.
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
// Initialize the flag to false.
nonNumberEntered = false;
// Determine whether the keystroke is a number from the top of the keyboard.
if (e.KeyCode < Keys.D0 || e.KeyCode > Keys.D9)
{
// Determine whether the keystroke is a number from the keypad.
if (e.KeyCode < Keys.NumPad0 || e.KeyCode > Keys.NumPad9)
{
// Determine whether the keystroke is a backspace.
if (e.KeyCode != Keys.Back)
{
// A non-numerical keystroke was pressed.
// Set the flag to true and evaluate in KeyPress event.
nonNumberEntered = true;
}
}
}
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (nonNumberEntered == true)
{
MessageBox.Show("Please enter number only...");
e.Handled = true;
}
}
source http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keypress(v=VS.90).aspx
3) using the MaskedTextBox: http://msdn.microsoft.com/en-us/library/system.windows.forms.maskedtextbox.aspx

wpf attribute instead of e.keychar in c#

I created a textbox dynamically with a TextChangedEventArgs to restrict the textbox to enter only numbers and decimal point.
Following is the code in c#
const char Delete = (char)8;
if (Char.IsDigit(e.KeyChar))
{
e.Handled = false;
}
else if (e.KeyChar == Delete)
{
e.Handled = false;
}
else if (e.KeyChar == '.')
{
if (!(amt.Text.Contains(".")))
e.Handled = false;
else
{
e.Handled = true;
}
}
else
{
e.Handled = true;
}
But I can't use this in wpf.
I tried to change the code with e.key or e.Text. But both these are not available. It is showing the following error Are u missing an assembly or directive.
Please anyone help me.
// one solution for filtering characters in a textbox.
// this is the PreviewKeyDown handler for a textbox named tbNumerical
// Need to add logic for cancelling repeated decimal point and minus sign
// or possible notation like 1.23e2 == 123
private void tbNumerical_PreviewKeyDown(object sender, KeyEventArgs e)
{
System.Windows.Input.Key k = e.Key;
// to see the key enums displayed, use a textbox or label
// someTextBox.Text = k.ToString();
// filter out control keys, not all are used, add more as needed
bool controlKeyIsDown = Keyboard.IsKeyDown(Key.LeftShift);
if (!controlKeyIsDown &&
Key.D0 <= k && k <= Key.D9 ||
Key.NumPad0 <= k && k <= Key.NumPad9 ||
k == Key.OemMinus || k == Key.Subtract ||
k == Key.Decimal || k == Key.OemPeriod) // or OemComma for european decimal point
else
{
e.Handled = true;
// just a little sound effect for wrong key pressed
System.Media.SystemSound ss = System.Media.SystemSounds.Beep;
ss.Play();
}
}

How do I make a textbox that only accepts numbers?

I have a windows forms app with a textbox control that I want to only accept integer values. In the past I've done this kind of validation by overloading the KeyPress event and just removing characters which didn't fit the specification. I've looked at the MaskedTextBox control but I'd like a more general solution that could work with perhaps a regular expression, or depend on the values of other controls.
Ideally this would behave such that pressing a non numeric character would either produce no result or immediately provide the user with feedback about the invalid character.
Two options:
Use a NumericUpDown instead. NumericUpDown does the filtering for you, which is nice. Of course it also gives your users the ability to hit the up and down arrows on the keyboard to increment and decrement the current value.
Handle the appropriate keyboard events to prevent anything but numeric input. I've had success with this two event handlers on a standard TextBox:
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) &&
(e.KeyChar != '.'))
{
e.Handled = true;
}
// only allow one decimal point
if ((e.KeyChar == '.') && ((sender as TextBox).Text.IndexOf('.') > -1))
{
e.Handled = true;
}
}
You can remove the check for '.' (and the subsequent check for more than one '.') if your TextBox shouldn't allow decimal places. You could also add a check for '-' if your TextBox should allow negative values.
If you want to limit the user for number of digit, use: textBox1.MaxLength = 2; // this will allow the user to enter only 2 digits
And just because it's always more fun to do stuff in one line...
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = !char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar);
}
NOTE: This DOES NOT prevent a user from Copy / Paste into this textbox. It's not a fail safe way to sanitize your data.
I am assuming from context and the tags you used that you are writing a .NET C# app. In this case, you can subscribe to the text changed event, and validate each key stroke.
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (System.Text.RegularExpressions.Regex.IsMatch(textBox1.Text, "[^0-9]"))
{
MessageBox.Show("Please enter only numbers.");
textBox1.Text = textBox1.Text.Remove(textBox1.Text.Length - 1);
}
}
Here is a simple standalone Winforms custom control, derived from the standard TextBox, that allows only System.Int32 input (it could be easily adapted for other types such as System.Int64, etc.). It supports copy/paste operations and negative numbers:
public class Int32TextBox : TextBox
{
protected override void OnKeyPress(KeyPressEventArgs e)
{
base.OnKeyPress(e);
NumberFormatInfo fi = CultureInfo.CurrentCulture.NumberFormat;
string c = e.KeyChar.ToString();
if (char.IsDigit(c, 0))
return;
if ((SelectionStart == 0) && (c.Equals(fi.NegativeSign)))
return;
// copy/paste
if ((((int)e.KeyChar == 22) || ((int)e.KeyChar == 3))
&& ((ModifierKeys & Keys.Control) == Keys.Control))
return;
if (e.KeyChar == '\b')
return;
e.Handled = true;
}
protected override void WndProc(ref System.Windows.Forms.Message m)
{
const int WM_PASTE = 0x0302;
if (m.Msg == WM_PASTE)
{
string text = Clipboard.GetText();
if (string.IsNullOrEmpty(text))
return;
if ((text.IndexOf('+') >= 0) && (SelectionStart != 0))
return;
int i;
if (!int.TryParse(text, out i)) // change this for other integer types
return;
if ((i < 0) && (SelectionStart != 0))
return;
}
base.WndProc(ref m);
}
Update 2017: My first answer has some issues:
you can type something that's longer than an integer of a given type (for example 2147483648 is greater than Int32.MaxValue);
more generally, there's no real validation of the result of what has been typed;
it only handles int32, you'll have to write specific TextBox derivated control for each type (Int64, etc.)
So I came up with another version that's more generic, that still supports copy/paste, + and - sign, etc.
public class ValidatingTextBox : TextBox
{
private string _validText;
private int _selectionStart;
private int _selectionEnd;
private bool _dontProcessMessages;
public event EventHandler<TextValidatingEventArgs> TextValidating;
protected virtual void OnTextValidating(object sender, TextValidatingEventArgs e) => TextValidating?.Invoke(sender, e);
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (_dontProcessMessages)
return;
const int WM_KEYDOWN = 0x100;
const int WM_ENTERIDLE = 0x121;
const int VK_DELETE = 0x2e;
bool delete = m.Msg == WM_KEYDOWN && (int)m.WParam == VK_DELETE;
if ((m.Msg == WM_KEYDOWN && !delete) || m.Msg == WM_ENTERIDLE)
{
DontProcessMessage(() =>
{
_validText = Text;
_selectionStart = SelectionStart;
_selectionEnd = SelectionLength;
});
}
const int WM_CHAR = 0x102;
const int WM_PASTE = 0x302;
if (m.Msg == WM_CHAR || m.Msg == WM_PASTE || delete)
{
string newText = null;
DontProcessMessage(() =>
{
newText = Text;
});
var e = new TextValidatingEventArgs(newText);
OnTextValidating(this, e);
if (e.Cancel)
{
DontProcessMessage(() =>
{
Text = _validText;
SelectionStart = _selectionStart;
SelectionLength = _selectionEnd;
});
}
}
}
private void DontProcessMessage(Action action)
{
_dontProcessMessages = true;
try
{
action();
}
finally
{
_dontProcessMessages = false;
}
}
}
public class TextValidatingEventArgs : CancelEventArgs
{
public TextValidatingEventArgs(string newText) => NewText = newText;
public string NewText { get; }
}
For Int32, you can either derive from it, like this:
public class Int32TextBox : ValidatingTextBox
{
protected override void OnTextValidating(object sender, TextValidatingEventArgs e)
{
e.Cancel = !int.TryParse(e.NewText, out int i);
}
}
or w/o derivation, use the new TextValidating event like this:
var vtb = new ValidatingTextBox();
...
vtb.TextValidating += (sender, e) => e.Cancel = !int.TryParse(e.NewText, out int i);
but what's nice is it works with any string, and any validation routine.
This is exactly what the Validated/Validating events were designed for.
Here's the MSDN article on the topic: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.validating.aspx
The TL;DR version: check the .Text property in the Validating event and set e.Cancel=True when the data is invalid.
When you set e.Cancel=True, the user can't leave the field, but you will need to give them some kind of feedback that something's wrong. I change the box's background color to light red to indicate a problem. Make sure to set it back to SystemColors.Window when Validating is called with a good value.
Try a MaskedTextBox. It takes a simple mask format so you can limit the input to numbers or dates or whatever.
You can use the TextChanged event
private void textBox_BiggerThan_TextChanged(object sender, EventArgs e)
{
long a;
if (! long.TryParse(textBox_BiggerThan.Text, out a))
{
// If not int clear textbox text or Undo() last operation
textBox_LessThan.Clear();
}
}
This might be useful. It allows "real" numeric values, including proper decimal points and preceding plus or minus signs. Call it from within the related KeyPress event.
private bool IsOKForDecimalTextBox(char theCharacter, TextBox theTextBox)
{
// Only allow control characters, digits, plus and minus signs.
// Only allow ONE plus sign.
// Only allow ONE minus sign.
// Only allow the plus or minus sign as the FIRST character.
// Only allow ONE decimal point.
// Do NOT allow decimal point or digits BEFORE any plus or minus sign.
if (
!char.IsControl(theCharacter)
&& !char.IsDigit(theCharacter)
&& (theCharacter != '.')
&& (theCharacter != '-')
&& (theCharacter != '+')
)
{
// Then it is NOT a character we want allowed in the text box.
return false;
}
// Only allow one decimal point.
if (theCharacter == '.'
&& theTextBox.Text.IndexOf('.') > -1)
{
// Then there is already a decimal point in the text box.
return false;
}
// Only allow one minus sign.
if (theCharacter == '-'
&& theTextBox.Text.IndexOf('-') > -1)
{
// Then there is already a minus sign in the text box.
return false;
}
// Only allow one plus sign.
if (theCharacter == '+'
&& theTextBox.Text.IndexOf('+') > -1)
{
// Then there is already a plus sign in the text box.
return false;
}
// Only allow one plus sign OR minus sign, but not both.
if (
(
(theCharacter == '-')
|| (theCharacter == '+')
)
&&
(
(theTextBox.Text.IndexOf('-') > -1)
||
(theTextBox.Text.IndexOf('+') > -1)
)
)
{
// Then the user is trying to enter a plus or minus sign and
// there is ALREADY a plus or minus sign in the text box.
return false;
}
// Only allow a minus or plus sign at the first character position.
if (
(
(theCharacter == '-')
|| (theCharacter == '+')
)
&& theTextBox.SelectionStart != 0
)
{
// Then the user is trying to enter a minus or plus sign at some position
// OTHER than the first character position in the text box.
return false;
}
// Only allow digits and decimal point AFTER any existing plus or minus sign
if (
(
// Is digit or decimal point
char.IsDigit(theCharacter)
||
(theCharacter == '.')
)
&&
(
// A plus or minus sign EXISTS
(theTextBox.Text.IndexOf('-') > -1)
||
(theTextBox.Text.IndexOf('+') > -1)
)
&&
// Attempting to put the character at the beginning of the field.
theTextBox.SelectionStart == 0
)
{
// Then the user is trying to enter a digit or decimal point in front of a minus or plus sign.
return false;
}
// Otherwise the character is perfectly fine for a decimal value and the character
// may indeed be placed at the current insertion position.
return true;
}
Just use a NumericUpDown control and set those ugly up down buttons visibility to false.
numericUpDown1.Controls[0].Visible = false;
NumericUpDown is actually a collection of controls containing a 'spin box' (up down buttons), a text box and some code to validate and wange-jangle it all together.
Marking:
YourNumericUpDown.Controls[0].visible = false
will hide the buttons while keeping the underlying code active.
While not being an obvious solution it is simple and effective. .Controls[1] would hide the text box portion if you wanted to do that instead.
I've been working on a collection of components to complete missing stuff in WinForms, here it is: Advanced Forms
In particular this is the class for a Regex TextBox
/// <summary>Represents a Windows text box control that only allows input that matches a regular expression.</summary>
public class RegexTextBox : TextBox
{
[NonSerialized]
string lastText;
/// <summary>A regular expression governing the input allowed in this text field.</summary>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public virtual Regex Regex { get; set; }
/// <summary>A regular expression governing the input allowed in this text field.</summary>
[DefaultValue(null)]
[Category("Behavior")]
[Description("Sets the regular expression governing the input allowed for this control.")]
public virtual string RegexString {
get {
return Regex == null ? string.Empty : Regex.ToString();
}
set {
if (string.IsNullOrEmpty(value))
Regex = null;
else
Regex = new Regex(value);
}
}
protected override void OnTextChanged(EventArgs e) {
if (Regex != null && !Regex.IsMatch(Text)) {
int pos = SelectionStart - Text.Length + (lastText ?? string.Empty).Length;
Text = lastText;
SelectionStart = Math.Max(0, pos);
}
lastText = Text;
base.OnTextChanged(e);
}
}
Simply adding something like myNumbericTextBox.RegexString = "^(\\d+|)$"; should suffice.
simply use this code in textbox :
private void textBox1_TextChanged(object sender, EventArgs e)
{
double parsedValue;
if (!double.TryParse(textBox1.Text, out parsedValue))
{
textBox1.Text = "";
}
}
Both integers and floats need to be accepted, including the negative numbers.
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
// Text
string text = ((Control) sender).Text;
// Is Negative Number?
if (e.KeyChar == '-' && text.Length == 0)
{
e.Handled = false;
return;
}
// Is Float Number?
if (e.KeyChar == '.' && text.Length > 0 && !text.Contains("."))
{
e.Handled = false;
return;
}
// Is Digit?
e.Handled = (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar));
}
I have made something for this on CodePlex.
It works by intercepting the TextChanged event. If the result is a good number it will be stored. If it is something wrong, the last good value will be restored. The source is a bit too large to publish here, but here is a link to the class that handles the core of this logic.
In our webpage with the definition of textbox we can add an onkeypress event for accepting only numbers. It will not show any message but it will prevent you from wrong input. It worked for me, user could not enter anything except number.
<asp:TextBox runat="server" ID="txtFrom"
onkeypress="if(isNaN(String.fromCharCode(event.keyCode))) return false;">
This is my aproach:
using linq (easy to modify filter)
copy/paste proof code
keeps caret position when you press a forbidden character
accepts left zeroes
and any size numbers
private void numeroCuenta_TextChanged(object sender, EventArgs e)
{
string org = numeroCuenta.Text;
string formated = string.Concat(org.Where(c => (c >= '0' && c <= '9')));
if (formated != org)
{
int s = numeroCuenta.SelectionStart;
if (s > 0 && formated.Length > s && org[s - 1] != formated[s - 1]) s--;
numeroCuenta.Text = formated;
numeroCuenta.SelectionStart = s;
}
}
This is a nice and short way to do it with .NET 5/Core
private void textBox1_KeyDown(object sender, KeyEventArgs e) {
if (e.KeyData != Keys.Back)
e.SuppressKeyPress = !int.TryParse(Convert.ToString((char) e.KeyData), out int _);
}
Edit: Added support for backspace key
you could use TextChanged/ Keypress event, use a regex to filter on numbers and take some action.
I would handle it in the KeyDown event.
void TextBox_KeyDown(object sender, KeyEventArgs e)
{
char c = Convert.ToChar(e.PlatformKeyCode);
if (!char.IsDigit(c))
{
e.Handled = true;
}
}
private void txt3_KeyPress(object sender, KeyPressEventArgs e)
{
for (int h = 58; h <= 127; h++)
{
if (e.KeyChar == h) //58 to 127 is alphabets tat will be blocked
{
e.Handled = true;
}
}
for(int k=32;k<=47;k++)
{
if (e.KeyChar == k) //32 to 47 are special characters tat will
{ be blocked
e.Handled = true;
}
}
}
try this is very simple
Take a look at Input handling in WinForm
I have posted my solution which uses the ProcessCmdKey and OnKeyPress events on the textbox. The comments show you how to use a Regex to verify the keypress and block/allow appropriately.
Hi you can do something like this in the textchanged event of the textbox.
here is a demo
private void textBox1_TextChanged(object sender, EventArgs e)
{
string actualdata = string.Empty;
char[] entereddata = textBox1.Text.ToCharArray();
foreach (char aChar in entereddata.AsEnumerable())
{
if (Char.IsDigit(aChar))
{
actualdata = actualdata + aChar;
// MessageBox.Show(aChar.ToString());
}
else
{
MessageBox.Show(aChar + " is not numeric");
actualdata.Replace(aChar, ' ');
actualdata.Trim();
}
}
textBox1.Text = actualdata;
}
It seems like many of the current answers to this question are manually parsing the input text. If you're looking for a specific built-in numeric type (e.g. int or double), why not just delegate the work to that type's TryParse method? For example:
public class IntTextBox : TextBox
{
string PreviousText = "";
int BackingResult;
public IntTextBox()
{
TextChanged += IntTextBox_TextChanged;
}
public bool HasResult { get; private set; }
public int Result
{
get
{
return HasResult ? BackingResult : default(int);
}
}
void IntTextBox_TextChanged(object sender, EventArgs e)
{
HasResult = int.TryParse(Text, out BackingResult);
if (HasResult || string.IsNullOrEmpty(Text))
{
// Commit
PreviousText = Text;
}
else
{
// Revert
var changeOffset = Text.Length - PreviousText.Length;
var previousSelectionStart =
Math.Max(0, SelectionStart - changeOffset);
Text = PreviousText;
SelectionStart = previousSelectionStart;
}
}
}
If you want something more generic but still compatible with Visual Studio's Designer:
public class ParsableTextBox : TextBox
{
TryParser BackingTryParse;
string PreviousText = "";
object BackingResult;
public ParsableTextBox()
: this(null)
{
}
public ParsableTextBox(TryParser tryParse)
{
TryParse = tryParse;
TextChanged += ParsableTextBox_TextChanged;
}
public delegate bool TryParser(string text, out object result);
public TryParser TryParse
{
set
{
Enabled = !(ReadOnly = value == null);
BackingTryParse = value;
}
}
public bool HasResult { get; private set; }
public object Result
{
get
{
return GetResult<object>();
}
}
public T GetResult<T>()
{
return HasResult ? (T)BackingResult : default(T);
}
void ParsableTextBox_TextChanged(object sender, EventArgs e)
{
if (BackingTryParse != null)
{
HasResult = BackingTryParse(Text, out BackingResult);
}
if (HasResult || string.IsNullOrEmpty(Text))
{
// Commit
PreviousText = Text;
}
else
{
// Revert
var changeOffset = Text.Length - PreviousText.Length;
var previousSelectionStart =
Math.Max(0, SelectionStart - changeOffset);
Text = PreviousText;
SelectionStart = previousSelectionStart;
}
}
}
And finally, if you want something fully generic and don't care about Designer support:
public class ParsableTextBox<T> : TextBox
{
TryParser BackingTryParse;
string PreviousText;
T BackingResult;
public ParsableTextBox()
: this(null)
{
}
public ParsableTextBox(TryParser tryParse)
{
TryParse = tryParse;
TextChanged += ParsableTextBox_TextChanged;
}
public delegate bool TryParser(string text, out T result);
public TryParser TryParse
{
set
{
Enabled = !(ReadOnly = value == null);
BackingTryParse = value;
}
}
public bool HasResult { get; private set; }
public T Result
{
get
{
return HasResult ? BackingResult : default(T);
}
}
void ParsableTextBox_TextChanged(object sender, EventArgs e)
{
if (BackingTryParse != null)
{
HasResult = BackingTryParse(Text, out BackingResult);
}
if (HasResult || string.IsNullOrEmpty(Text))
{
// Commit
PreviousText = Text;
}
else
{
// Revert
var changeOffset = Text.Length - PreviousText.Length;
var previousSelectionStart =
Math.Max(0, SelectionStart - changeOffset);
Text = PreviousText;
SelectionStart = previousSelectionStart;
}
}
}
Using the approach described in Fabio Iotti's answer I have created a more generic solution:
public abstract class ValidatedTextBox : TextBox {
private string m_lastText = string.Empty;
protected abstract bool IsValid(string text);
protected sealed override void OnTextChanged(EventArgs e) {
if (!IsValid(Text)) {
var pos = SelectionStart - Text.Length + m_lastText.Length;
Text = m_lastText;
SelectionStart = Math.Max(0, pos);
}
m_lastText = Text;
base.OnTextChanged(e);
}
}
"ValidatedTextBox", which contains all nontrivial validation behavior.
All that's left to do is inherit from this class and override "IsValid" method with whatever validation logic is required.
For example, using this class, it is possible to create "RegexedTextBox" which will accept only strings which match specific regular expression:
public abstract class RegexedTextBox : ValidatedTextBox {
private readonly Regex m_regex;
protected RegexedTextBox(string regExpString) {
m_regex = new Regex(regExpString);
}
protected override bool IsValid(string text) {
return m_regex.IsMatch(Text);
}
}
After that, inheriting from the "RegexedTextBox" class, we can easily create "PositiveNumberTextBox" and "PositiveFloatingPointNumberTextBox" controls:
public sealed class PositiveNumberTextBox : RegexedTextBox {
public PositiveNumberTextBox() : base(#"^\d*$") { }
}
public sealed class PositiveFloatingPointNumberTextBox : RegexedTextBox {
public PositiveFloatingPointNumberTextBox()
: base(#"^(\d+\" + CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator + #")?\d*$") { }
}
Sorry to wake the dead, but I thought someone might find this useful for future reference.
Here is how I handle it. It handles floating point numbers, but can easily be modified for integers.
Basically you can only press 0 - 9 and .
You can only have one 0 before the .
All other characters are ignored and the cursor position maintained.
private bool _myTextBoxChanging = false;
private void myTextBox_TextChanged(object sender, EventArgs e)
{
validateText(myTextBox);
}
private void validateText(TextBox box)
{
// stop multiple changes;
if (_myTextBoxChanging)
return;
_myTextBoxChanging = true;
string text = box.Text;
if (text == "")
return;
string validText = "";
bool hasPeriod = false;
int pos = box.SelectionStart;
for (int i = 0; i < text.Length; i++ )
{
bool badChar = false;
char s = text[i];
if (s == '.')
{
if (hasPeriod)
badChar = true;
else
hasPeriod = true;
}
else if (s < '0' || s > '9')
badChar = true;
if (!badChar)
validText += s;
else
{
if (i <= pos)
pos--;
}
}
// trim starting 00s
while (validText.Length >= 2 && validText[0] == '0')
{
if (validText[1] != '.')
{
validText = validText.Substring(1);
if (pos < 2)
pos--;
}
else
break;
}
if (pos > validText.Length)
pos = validText.Length;
box.Text = validText;
box.SelectionStart = pos;
_myTextBoxChanging = false;
}
Here is a quickly modified int version:
private void validateText(TextBox box)
{
// stop multiple changes;
if (_myTextBoxChanging)
return;
_myTextBoxChanging = true;
string text = box.Text;
if (text == "")
return;
string validText = "";
int pos = box.SelectionStart;
for (int i = 0; i < text.Length; i++ )
{
char s = text[i];
if (s < '0' || s > '9')
{
if (i <= pos)
pos--;
}
else
validText += s;
}
// trim starting 00s
while (validText.Length >= 2 && validText.StartsWith("00"))
{
validText = validText.Substring(1);
if (pos < 2)
pos--;
}
if (pos > validText.Length)
pos = validText.Length;
box.Text = validText;
box.SelectionStart = pos;
_myTextBoxChanging = false;
}
This one works with copy and paste, drag and drop, key down, prevents overflow and is pretty simple
public partial class IntegerBox : TextBox
{
public IntegerBox()
{
InitializeComponent();
this.Text = 0.ToString();
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
}
private String originalValue = 0.ToString();
private void Integerbox_KeyPress(object sender, KeyPressEventArgs e)
{
originalValue = this.Text;
}
private void Integerbox_TextChanged(object sender, EventArgs e)
{
try
{
if(String.IsNullOrWhiteSpace(this.Text))
{
this.Text = 0.ToString();
}
this.Text = Convert.ToInt64(this.Text.Trim()).ToString();
}
catch (System.OverflowException)
{
MessageBox.Show("Value entered is to large max value: " + Int64.MaxValue.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
this.Text = originalValue;
}
catch (System.FormatException)
{
this.Text = originalValue;
}
catch (System.Exception ex)
{
this.Text = originalValue;
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK , MessageBoxIcon.Error);
}
}
}
Do not forget that a user can paste an invalid text in a TextBox.
If you want to restrict that, follow the below code:
private void ultraTextEditor1_TextChanged(object sender, EventArgs e)
{
string append="";
foreach (char c in ultraTextEditor1.Text)
{
if ((!Char.IsNumber(c)) && (c != Convert.ToChar(Keys.Back)))
{
}
else
{
append += c;
}
}
ultraTextEditor1.Text = append;
}
I was also looking for the best way to check only numbers in textbox and problem with keypress was it does not support copy paste by right click or clipboard so came up with this code which validates the when cursor leaves the text field and also it checks for empty field. (adapted version of newguy)
private void txtFirstValue_MouseLeave(object sender, EventArgs e)
{
int num;
bool isNum = int.TryParse(txtFirstValue.Text.Trim(), out num);
if (!isNum && txtFirstValue.Text != String.Empty)
{
MessageBox.Show("The First Value You Entered Is Not a Number, Please Try Again", "Invalid Value Detected", MessageBoxButtons.OK, MessageBoxIcon.Error);
txtFirstValue.Clear();
}
}
Here are more than 30 answers and a lot of answers are helpful. But I want to share a generalized form for the System.Windows.Forms.TextBox and System.Windows.Controls.TextBox.
There is not available KeyPress event in System.Windows.Controls.TextBox.
This answer is for those people who want to implement with the same logic for System.Windows.Forms.TextBox and System.Windows.Controls.TextBox.
This is NumberTextBox code. Use commented line instead of the previous line for System.Windows.Controls.TextBox.
public class NumberTextBox : System.Windows.Forms.TextBox
//public class NumberTextBox : System.Windows.Controls.TextBox
{
private double _maxValue;
private double _minValue;
private bool _flag;
private string _previousValue;
public NumberTextBox()
{
this.TextAlign = HorizontalAlignment.Right;
//TextAlignment = TextAlignment.Right;
KeyDown += TextBox_KeyDown;
TextChanged += TextBox_TextChanged;
_minValue = double.MinValue;
_maxValue = double.MaxValue;
}
private void TextBox_KeyDown(object sender, KeyEventArgs e)
{
_previousValue = this.Text;
_flag = this.SelectedText.Length > 0;
}
private void TextBox_TextChanged(object sender, EventArgs e)
//private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var text = this.Text;
if (text.Length < 1) return;
var cursorPosition = SelectionStart == 0 ? SelectionStart : SelectionStart - 1;
var insertedChar = text[cursorPosition];
if (IsInvalidInput(insertedChar, cursorPosition, text))
{
HandleText(text, cursorPosition);
}
ValidateRange(text, cursorPosition);
}
private bool IsInvalidInput(char insertedChar, int cursorPosition, string text)
{
return !char.IsDigit(insertedChar) && insertedChar != '.' && insertedChar != '-' ||
insertedChar == '-' && cursorPosition != 0 ||
text.Count(x => x == '.') > 1 ||
text.Count(x => x == '-') > 1;
}
private void HandleText(string text, int cursorPosition)
{
this.Text = _flag ? _previousValue : text.Remove(cursorPosition, 1);
this.SelectionStart = cursorPosition;
this.SelectionLength = 0;
}
private void ValidateRange(string text, int cursorPosition)
{
try
{
if (text == "." || _minValue < 0 && text == "-") return;
var doubleValue = Convert.ToDouble(text);
if (doubleValue > _maxValue || doubleValue < _minValue)
{
HandleText(text, cursorPosition);
}
}
catch (Exception)
{
HandleText(text, cursorPosition);
}
}
protected void SetProperties(double minValue = double.MinValue, double maxValue = double.MaxValue)
{
_minValue = minValue;
_maxValue = maxValue;
}
}
PositiveNumberTextBox code:
public class PositiveNumberTextBox : NumberTextBox
{
public PositiveNumberTextBox()
{
SetProperties(0);
}
}
FractionNumberTextBox code:
public class FractionNumberTextBox : NumberTextBox
{
public FractionNumberTextBox()
{
SetProperties(0, 0.999999);
}
}
int Number;
bool isNumber;
isNumber = int32.TryPase(textbox1.text, out Number);
if (!isNumber)
{
(code if not an integer);
}
else
{
(code if an integer);
}
3 solution
1)
//Add to the textbox's KeyPress event
//using Regex for number only textBox
private void txtBox_KeyPress(object sender, KeyPressEventArgs e)
{
if (!System.Text.RegularExpressions.Regex.IsMatch(e.KeyChar.ToString(), "\\d+"))
e.Handled = true;
}
2)
an another solution from msdn
// Boolean flag used to determine when a character other than a number is entered.
private bool nonNumberEntered = false;
// Handle the KeyDown event to determine the type of character entered into the control.
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
// Initialize the flag to false.
nonNumberEntered = false;
// Determine whether the keystroke is a number from the top of the keyboard.
if (e.KeyCode < Keys.D0 || e.KeyCode > Keys.D9)
{
// Determine whether the keystroke is a number from the keypad.
if (e.KeyCode < Keys.NumPad0 || e.KeyCode > Keys.NumPad9)
{
// Determine whether the keystroke is a backspace.
if (e.KeyCode != Keys.Back)
{
// A non-numerical keystroke was pressed.
// Set the flag to true and evaluate in KeyPress event.
nonNumberEntered = true;
}
}
}
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (nonNumberEntered == true)
{
MessageBox.Show("Please enter number only...");
e.Handled = true;
}
}
source http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keypress(v=VS.90).aspx
3) using the MaskedTextBox: http://msdn.microsoft.com/en-us/library/system.windows.forms.maskedtextbox.aspx

Categories

Resources