using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace JRCookbookControls { [System.Serializable()] public class JRCookbookNumericTextBox: TextBox { private String _strLastValue = String.Empty; private bool _blnAllowNegative = true; private bool _blnAllowDecimal = true; private bool _blnAllowEmpty = true; public JRCookbookNumericTextBox() { this.TextChanged += new System.EventHandler(this.NumericTextBox_TextChanged); this.Validating += new System.ComponentModel.CancelEventHandler(this.NumericTextBox_Validating); } [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public bool AllowDecimal { get { return _blnAllowDecimal; } set { _blnAllowDecimal = value; } } [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public bool AllowNegative { get { return _blnAllowNegative; } set { _blnAllowNegative = value; } } [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public bool AllowEmpty { get { return _blnAllowEmpty; } set { _blnAllowEmpty = value; } } private void NumericTextBox_TextChanged(System.Object sender, System.EventArgs e) { bool blnValueIsOK = true; Int32 intPosition = 0; bool blnAlreadySeenDecimal = false; //Allow digits, one decimal point, and minus sign (if first character only) foreach (char chrCharacter in this.Text) { switch (chrCharacter) { case char x when (x >= '0' && x <= '9'): //OK break; case '-': if (intPosition > 0 || AllowNegative == false) { blnValueIsOK = false; } break; case '.': if (blnAlreadySeenDecimal) { blnValueIsOK = false; } else { blnAlreadySeenDecimal = true; } break; default: blnValueIsOK = false; break; } intPosition += 1; if (!blnValueIsOK) { break; } } if (blnValueIsOK) { _strLastValue = this.Text; } else { Int32 oldSelectionStart = this.SelectionStart - 1; this.Text = _strLastValue; if (oldSelectionStart >= 0 && oldSelectionStart <= this.Text.Length) { this.SelectionStart = oldSelectionStart; } } } private void NumericTextBox_Validating(System.Object sender, System.ComponentModel.CancelEventArgs e) { if (this.Text == String.Empty) { if (AllowEmpty) { return; } else { e.Cancel = true; } } //Now that we know it's not empty, make sure we have a digit foreach (char chrCharacter in this.Text) { switch (chrCharacter) { case char x when (x >= '0' && x <= '9'): //OK return; } } //If we got here, we have hyphen or period, but no digits e.Cancel = true; } } }