C# Custom control – TextBox accepting only numbers, decimal numbers, signed numbers
PROGRAMMING HELP 2017/10/05 00:51
The creation of custom control using Visual Studio involves the following steps:
- Start Visual Studio;
- Create new “Windows Control Library” project;
- In the created project delete “User Control” file;
- Go to “Project” > “Add User Control” and give it a name;
- Change the inherited class to this that you want your control to be;
- Create you custom properties for the control;
- Compile the project: Go to “Build” > “Build Solution”;
The generated DLL file is located in you projects folder under:
“bin/Debug/UserContolName.dll” or “bin/Release/UserContolName.dll”.
That depends on how your solution is configured: “Debug mode” or “Release mode”.
Once created the DLL file can be added as custom control to Visual Studio toolbox.
This example shows how to create custom text box control which accepts only numbers, decimal separator or negative sign.
By default the text box only accepts numbers: 0123456789, to be entered.
There are two properties that allows the user to enter only numbers with decimal separator or signed numbers.
If both properties are enabled then the text box accepts numbers, decimal separator and negative sign.
A tool tip is shown with information what the user can enter in the text box, if incorrect data is tried to be entered.
A placeholder (watermark) functionality is added using the paint event of the text box.
After creating the project delete the default "User Control" file.
Add new user control to project and name it “TextBoxNumbers”.
You can download the complete TextBoxNumbers project with test project included.
Or download only the TextBoxNumbers.dll control and include it in Visual Studio toolbox to start using it immediately.
Note:
The project is created in Visual Studio 2015.
TextBoxNumber control is targeting .Net Framework v3.5 and above.
The project is created in Visual Studio 2015.
TextBoxNumber control is targeting .Net Framework v3.5 and above.
// Change the class which is inherited from Control: public partial class TextBoxNumbers : System.Windows.Forms.Control // To TextBox: public partial class TextBoxNumbers : TextBox
// Create the custom properties for the text box: private bool isSigned = false; private bool isDecimal = false; private string toolTipText; // Where this is used will be show a little later private string placeHolder; // Set to true to accept negative numbers public bool IsSigned { set { isSigned = value; }} // Set to true to accep decimal numbers public bool IsDecimal{ set { isDecimal = value; }} // Set the text of the place holder public string PlaceHolder{ set { placeHolder = value; }} // ToolBox control is initialized by this function. // Function to set parameters of the tool tip and to show it. void ToolTipInitializer(string toolTipText) { // Parameters of the tool tip int toolTipPosX = this.Width; int toolTipPosY = 0; int toolTipDuration = 4000; ToolTip toolTip = new ToolTip(); // Set icon for the tool tip toolTip.ToolTipIcon = ToolTipIcon.Warning; // Show the tool tip toolTip.Show(toolTipText, this, toolTipPosX, toolTipPosY, toolTipDuration); } // The function to enter only numbers: // By default this is active. // Allow only numbers: 0123456789 private void Numbers(KeyPressEventArgs e) { // If the input is different from control key and digit key if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar)) { // Show the tool tip ToolTipInitializer(toolTipText); // Set Handled method to true to cancel the button press. e.Handled = true; } }
// The function to enter only signed numbers: // Allow numbers: 0123456789 // and negative sign private void SignedNumbers(KeyPressEventArgs e) { // Get negative sign according your computer settings char negativeSign = Convert.ToChar(CultureInfo.CurrentCulture.NumberFormat.NegativeSign); if (e.KeyChar == negativeSign) // If the negative sign key is pressed { if ((this.SelectionLength > 0) && this.Text.Contains(negativeSign)) // When the whole number is selected and contains negative sign allow to enter negative sign e.Handled = false; else if ((this.Text.Length > 0) && (this.SelectionStart != 0)) // Forbids entering negative sign when not in the very beginning e.Handled = true; else if (this.Text.Contains(negativeSign)) // If text box contains decimal separator, then e.Handled = true; // cancel the key press else e.Handled = false; // Allows entering negative sign in the very beginning } else if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar)) // If the input is different from control key and digit key { ToolTipInitializer(toolTipText); // Show tool tip e.Handled = true; // Cancel the key press } }
// The function to enter only decimal numbers: // Allows numbers: 0123456789 // and decimal separator private void DecimalNumbers(KeyPressEventArgs e) { // Get decimal separator according your computer settings char decimalSeparator = Convert.ToChar(CultureInfo.CurrentCulture. NumberFormat.NumberDecimalSeparator); if (e.KeyChar == decimalSeparator) // If the decimal separator key is pressed { // When the whore number is selected and contains decimal separator // allow to enter decimal separator if((this.SelectionLength > 0) && this.Text.Contains(decimalSeparator)) { this.Text = "0"; e.Handled = false; this.SelectionStart = this.TextLength; } else if (this.Text.Length == 0) { // If decimal separator key is pressed in the very beginning // then a zero is inserted before it this.Text = "0" + decimalSeparator; e.Handled = true; this.SelectionStart = this.TextLength; } // If text box contains decimal separator, then else if (this.Text.Contains(decimalSeparator)) e.Handled = true; // cancel the key press } // If the input is different from control key and digit key else if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar)) { ToolTipInitializer(toolTipText); // Show tooltip e.Handled = true; // Cancel the key press } }
// The function to enter both decimal and signed numbers: // Allows numbers: 0123456789, decimal separator and negative sign private void DecimalSignedNumbers(KeyPressEventArgs e) { char decimalSeparator = Convert.ToChar(CultureInfo.CurrentCulture. NumberFormat.NumberDecimalSeparator); char negativeSign = Convert.ToChar(CultureInfo.CurrentCulture. NumberFormat.NegativeSign); if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) && (e.KeyChar != decimalSeparator) && (e.KeyChar != negativeSign)) { ToolTipInitializer(toolTipText); e.Handled = true; } if (e.KeyChar == decimalSeparator) { if((this.SelectionLength > 0) && this.Text.Contains(decimalSeparator)) { this.Text = "0"; e.Handled = false; this.SelectionStart = this.TextLength; } else if (this.Text.Length == 0) { this.Text = "0" + decimalSeparator; e.Handled = true; this.SelectionStart = this.TextLength; } else if (this.Text.Contains(decimalSeparator)) e.Handled = true; } else if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar)) { ToolTipInitializer(toolTipText); e.Handled = true; } if (e.KeyChar == negativeSign) { if ((this.SelectionLength > 0) && this.Text.Contains(negativeSign)) e.Handled = false; else if ((this.Text.Length > 0) && (this.SelectionStart != 0)) e.Handled = true; else if (this.Text.Contains(negativeSign)) e.Handled = true; else e.Handled = false; } else if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar)) { ToolTipInitializer(toolTipText); e.Handled = true; } }
Overriding the OnKeyPress event of the text box.
Here the toolTipText property is initialized.
protected override void OnKeyPress(KeyPressEventArgs e) { base.OnKeyPress(e); // Check what numbers is accepting the text box // and set tool tip message according that if (isSigned && isDecimal) { toolTipText = "Input field can only contain the following characters:" + "\n\t- Numbers: 0123456789" + "\n\t- Decimal Separator" + "\n\t- Negative Sign"; DecimalSignedNumbers(e); } else if (isDecimal) { toolTipText = "Input field can only contain the following characters:" + "\n\t- Numbers: 0123456789" + "\n\t- Decimal Separator"; DecimalNumbers(e); } else if (isSigned) { toolTipText = "Input field can only contain the following characters:" + "\n\t- Numbers: 0123456789" + "\n\t- Negative sign"; SignedNumbers(e); } else { toolTipText = "Input field can only contain the following characters:" + "\n\t- Numbers: 0123456789"; Numbers(e); } }
Realization of the placeholder (watermark) functionality
The best way to create placeholder is to override the OnPaint event of the text box and to draw the desired text like this.
protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); SolidBrush myBrushDrawText = new SolidBrush(Color.DarkGray); // Set brush color Font drawFont = new Font("Microsoft Sans Serif", 8.25F); // Set font family and font size e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; // Set quality of the graphic // Draw the placeholder text e.Graphics.DrawString(placeHolder, drawFont, myBrushDrawText, new Point(0, 0)); }
The OnPaint event is ignored by default until modifying the control style UserPaint.
Create a function for toggling the placeholder on and off:
// Function to toggle the placeholder on/off private void PlaceHolder_Toggle(object sender, EventArgs e) { if (this.Text.Length <= 0) this.SetStyle(ControlStyles.UserPaint, true); // Placeholder - on else this.SetStyle(ControlStyles.UserPaint, false); // Placeholder - off }
Override OnCreateControl and call the PlaceHolder_Toggle function inside. This will guarantee that the toggle function of the placeholder will be called after the control is totally created.
protected override void OnCreateControl() { base.OnCreateControl(); PlaceHolder_Toggle(null, null); }
The following events must be subscribed in the constructor so the placeholder could be toggled according to the text box property “Text”.
public TextBoxNumbers() { InitializeComponent(); // No one of theese events will start, because // TextBox control is still in construction this.TextChanged += new EventHandler(this.PlaceHolder_Toggle); this.LostFocus += new EventHandler(this.PlaceHolder_Toggle); this.FontChanged += new EventHandler(this.PlaceHolder_Toggle); this.GotFocus += new EventHandler(this.PlaceHolder_Toggle); this.LostFocus += new EventHandler(this.PlaceHolder_Toggle); }