C# Custom control – TextBox accepting only numbers, decimal numbers, signed numbers

2016/07/29 21:38


The creation of custom control using Visual Studio involves the following steps:

  1. Start Visual Studio;
  2. Create new “Windows Control Library” project;
  3. In the created project delete “User Control” file;
  4. Go to “Project” > “Add User Control” and give it a name;
  5. Change the inherited class to this that you want your control to be;
  6. Create you custom properties for the control;
  7. 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.


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 laterprivate string placeHolder;// Set to true to accept negative numberspublic bool IsSigned{   set { isSigned = value; }}// Set to true to accep decimal numberspublic bool IsDecimal{   set { isDecimal = value; }}// Set the text of the place holderpublic 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: 0123456789private 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 signprivate 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 whore number is seleceted 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 separatorprivate 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    {        if((this.SelectionLength > 0) && this.Text.Contains(decimalSeparator)) // When the whore number is seleceted and contains decimal separator allow to enter decimal separator        {            this.Text = "0";            e.Handled = false;            this.SelectionStart = this.TextLength;        }        else if (this.Text.Length == 0) // If decimal separotr key is pressed in the verry beginning then a zero is inserted before it        {            this.Text = "0" + decimalSeparator;            e.Handled = true;            this.SelectionStart = this.TextLength;        }        else if (this.Text.Contains(decimalSeparator)) // If text box contains decimal separator, then            e.Handled = true;                          // cancel the key press    }    else if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar)) // If the input is different from control key and digit key    {        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 signprivate 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/offprivate 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);}