Search code examples
c#winformstextboxmaskedtextbox

Input only digits and control buttons


I want to input Salary with any value: 550,49, 2222,12, 9,3 and so on. But need to use control button like this: ,, backspace, ctrl + c, ctrl + v, ctrl + a.

Salary is TextBox with ShortcutsEnabled = true and event:

private void TbSalary_KeyPress(object sender, KeyPressEventArgs e)
{
    char number = e.KeyChar;
    if ((e.KeyChar <= 47 || e.KeyChar >= 58) && number != 8 && number != 44) 
         //digits, BackSpace and ,
    {
        e.Handled = true;
    }
}

If remove this condition, the specified combinations will work. But not only numbers are entered.

Should I add tracking of all combinations here? Or is it possible to implement this task in another way?

MaskedTextBox requires a fixed number of characters with some "mask". But the Salary is different. Can be **,**, ******,* or *** and etc.

UPDATE

Prevent entering more than two numbers after the decimal point

if (number < ' ')
{
    return;
}
if (number >= '0' && number <= '9')
{
    if (this.Text.Contains(',') 
        && this.SelectionLength == 0
        && this.SelectionStart > this.Text.IndexOf(',')
        && this.Text.Length - this.Text.IndexOf(',') > 2)
    {
        e.Handled = true;
    }

    return;
}

Solution

  • Please, don't use magic numbers like 47, let's work with characters. We should allow these characters:

    • '0'..'9' range (numbers)
    • control characters (which are below space ' ') for tab, backspace etc.
    • ',' (comma) as a decimal separator

    All the other characters should be banned.

    Code:

    private void TbSalary_KeyPress(object sender, KeyPressEventArgs e)
    {
        char number = e.KeyChar;
        TextBox box = sender as TextBox;
    
        if (number >= '0' && number <= '9' || number < ' ')
            return; // numbers as well as backspaces, tabs: business as usual
        else if (number == ',') {  
            // We don't want to allow several commas, right?
            int p = box.Text.IndexOf(',');
    
            // So if we have a comma already...
            if (p >= 0) { 
                // ... we don't add another one
                e.Handled = true;
    
                // but place caret after the comma position
                box.SelectionStart = p + 1;
                box.SelectionLength = 0;  
            }  
            else if (box.SelectionStart == 0) {
                // if we don't have comma and we try to add comma at the 1st position 
                e.Handled = true;
    
                // let's add it as "0,"
                box.Text = "0," + box.Text.Substring(box.SelectionLength);
                box.SelectionStart = 2;
           } 
        }
        else  
            e.Handled = true; // all the other characters (like '+', 'p') are banned
    }
    

    Please, note, that there is possibility to Paste incorrect value (say, "bla-bla-bla") into TbSalary TextBox; to prevent it you can use TextChanged event:

    private void TbSalary_TextChanged(object sender, EventArgs e) {
      TextBox box = sender as TextBox;
    
      StringBuilder sb = new StringBuilder();
    
      bool hasComma = false;
    
      foreach (var c in box.Text)
        if (c >= '0' && c <= '9')
          sb.Append(c);
        else if (c == ',' && !hasComma) {
          hasComma = true;
    
          if (sb.Length <= 0) // we don't start from comma
            sb.Append('0');
    
          sb.Append(c);
        }
    
      string text = sb.ToString();
    
      if (!text.Equals(box.Text))
        box.Text = text;
    }