-3

I have a textbox with both letters and numbers in and other symbols in which you can find on your keyboard. I have this code which works fine when I manually put the data in and it only lets me put numbers in and deletes letters. Everything what I want, apart from none of it works if the data is copied and pasted in. Below is my code.

private void textBox7_TextChanged(object sender, EventArgs e)
{
    Exception X = new Exception();

    TextBox T = (TextBox)sender;

    T.Text = T.Text.Trim();
    try
    {
        if (T.Text != "-")
        {
            int x = int.Parse(T.Text);
        }
    }
    catch (Exception)
    {
        try
        {
            int CursorIndex = T.SelectionStart - 1;
            T.Text = T.Text.Remove(CursorIndex, 1);

            //Align Cursor to same index
            T.SelectionStart = CursorIndex;
            T.SelectionLength = 0;
        }
        catch (Exception) { }

    }
}
user3290171
  • 121
  • 1
  • 3
  • 19
  • Please post code that compile. You had a lot of wrong brackets which I fixed for you. – gunr2171 Sep 25 '14 at 17:56
  • Try adding a breakpoint and then pasting the text again?... I wonder if the paste is throwing in the whole string, as opposed to typing manually where the TextChanged method will be called once per character... – Ian Sep 25 '14 at 18:00
  • @Ian That is exactly what paste does. – juharr Sep 25 '14 at 18:04
  • 1
    Consider using a NumericUpDown control rather than a TextBox? – Ian Sep 25 '14 at 18:07
  • You may also want to take a look at this question [How do I make a textbox that only accepts numbers?](http://stackoverflow.com/questions/463299/how-do-i-make-a-textbox-that-only-accepts-numbers) or this article on MSDN [How to: Create a Numeric Text Box](http://msdn.microsoft.com/en-us/library/ms229644%28v=vs.80%29.aspx) – Roman Sep 25 '14 at 18:09

4 Answers4

0

To remove non-numeric characters from the textbox's text, try a regular expression replacement using Regex.Replace

private void numericTextbox_TextChanged(object sender, EventArgs e)
{
    TextBox tb = (TextBox)sender;
    tb.Text = Regex.Replace(tb.Text, "\\-?[^\d]", "");
}

This will replace any non-numeric character (except a dash at the front, for negative numbers) in your text with nothing every time the text in the box changes, whether the user types something directly or pastes in text from somewhere else.

Alternatively, if you want to keep any dashes (for, say, a phone number):

tb.Text = Regex.Replace(tb.Text, "\\[^-\d]", "");
0

Basically your problem is that pasting a value will only call the TextChanged event once for the entire change. Your code is relying on the event being called for each character that is put into the textbox.

It sounds like all you really want to do is filter all non numeric values after a possible negative sign. If that is the case you can do it like this.

private void textBox7_TextChanged(object sender, EventArgs e)
{
    textBox7.Text = string.Concat(
        textBox7.Text.Trim().Where((c,i)=>char.IsDigit(c) || (i==0 && c=='-')));
}

This code is using Linq to go through each character, after trimming leading and trailing white space, and only keeping the ones that are digits or a negative sign if it is the first character. It's equivalent to the following.

private void textBox7_TextChanged(object sender, EventArgs e)
{
    StringBuilder builder = new StringBuilder()
    string trimmed = textBox7.Text.Trim();
    for(int i=0; i<trimmed.Length; i++)
    {
        char c = trimmed.Text[i];
        if(char.IsDigit(c) || (i==0 && c=='-'))
        {
            builder.Append(c);
        }
    }

    textBox7.Text = builder.ToString();
}
juharr
  • 31,741
  • 4
  • 58
  • 93
0

The problem with your current code is that you're removing only the last entered character from the cursor position. Pasting text with more than a character breaks your algo.

So let's say you're pasting in 9 letters, the CursorIndex is at 9, you remove only one character (that's the T.Text = T.Text.Remove(CursorIndex, 1); line) and you're left with 8 incorrect ones left.

A better approach (which isn't overly complex like yours) would look like this :

private void textBox7_TextChanged(object sender, EventArgs e)
{
    textBox7.Text = string.Concat(textBox7.Text.Where(char.IsDigit));
}

So here we're replacing on each change the text with a new text containing each characters that passes the char.IsDigit test. The cursor won't be at the good position however. Unless multiple edits in the middle of the string are expected, it's probably best to only strap a

textBox1.SelectionStart = textBox1.Text.Length;

at the end of the method, it'll handle pasted text too.

To handle the case where you don't want to erase the character - when it is the only text in your textbox, you can add an obvious if condition. Globally, it'll look like this:

private void textBox7_TextChanged(object sender, EventArgs e)
{
    if (textbox7.Text != "-")
        textBox7.Text = string.Concat(textBox7.Text.Where(char.IsDigit));

    textBox1.SelectionStart = textBox1.Text.Length;
}
Pierre-Luc Pineault
  • 8,993
  • 6
  • 40
  • 55
0

Try this. It saves the old value in a var and if the new value cannot be parsed, it reverts the text to old. Otherwise it updates old to the most recent valid value. It's a different approach then you took, but much simpler in my opinion.

string old;
private void textBox7_TextChanged(object sender, EventArgs e) {
    int i;
    if (textBox1.Text == "" || int.TryParse(textBox7.Text, out i)) {
        old = textBox7.Text;
    } else {
        textBox7.Text = old;
    }
}
Oskar Hýbl
  • 401
  • 3
  • 9