Introduction
In some applications we need to show the input text in a TextBox with some mask, like, for example, a currency mask to make it more easy to read and understand.
In my case, I needed to put text, and additionally, the currency symbol, once the text was written. To do that, I decided to develop a control that inherits from
the original TextBox
control and implements some new members to allow the control to validate and show the input text with the currency mask we need.
Background
Here is a brief explanation...
TextBox (System.Windows.Forms.TextBox)
The TextBox
control is one of the basic and most used controls in WinForms applications that allows the user to input text to interact with the application.
It has basics behaviors and members that allow us to use it instantly without having to add anything to the control.
Based on the TextBox
control, we are going to develop a TextBox that can mask our input text with currency format, including the currency symbol that we want.
Inheritance
Inheritance is a way to compartmentalize and reuse code by creating objects that have attributes and behaviors that can be based on previously created objects.
Inheritance allows us to work with simple controls like TextBox
by taking advantage of their basic behaviors and lets us improve the control by adding new members
to control some behaviors that we need to.
In Visual C#, we can write a class definition that inherits from TextBox
like this:
public partial class customTextBox : System.Windows.Forms.TextBox
Method overriding
It's a feature that allows a child class to provide a specific implementation of a method that's already provided by its parent class.
As an example, in Visual C#, we can override a method from a parent class by writing:
protected override void OnLostFocus(EventArgs e)
{
this.Text = formatText();
base.OnLostFocus(e);
}
Development
Here is an explanation of the code behind the currencyTextBox
:
The currencyTextBox control library
The Control Library JRINCCustomControls only contains the currencyTextBox
control, and you can add this to your ToolBox in Visual Studio:
...or can reference it as a DLL component directly in your project:
The demo project
The demo project will show you how to implement the currencyTextBox
control in a WinForms project, where you can test anything you want about the control.
The code
Now I'll explain the different members I've added to the new textbox and how they work.
In the currencyTextBox
class in the JRINCCustomControls project are various custom members that help us achieve the goal
of putting the currency-mask to our input text. These are:
Public properties
WorkingText (public string)
It's a read only property that contains our "working text". That means that it contains exactly what the user typed in the TextBox, the text without any mask or formatting.
Definition:
private string _workingText;
public string WorkingText
{
get { return _workingText; }
private set { _workingText = value; }
}
PreFix (public string)
It's a public property that can be assigned and retrieved. It must contain the prefix or currency symbol that we want to precede the input text with. If empty, no prefix
is used on the masked text. It can be assigned through the Properties window at design time.
Default value: Empty.
Definition:
private string _preFix;
public string PreFix
{
get { return _preFix; }
set { _preFix = value; }
}
ThousandsSeparator (public char)
It's a public property that can be assigned and retrieved. It must contain the separator symbol for thousands that we want our input text to show when masked.
If empty, no thousands separator is used on the masked text. It can be assigned through the Properties window at design time.
Default value: ','.
Definition:
private char _thousandsSeparator = ',';
public char ThousandsSeparator
{
get { return _thousandsSeparator; }
set { _thousandsSeparator = value; }
}
DecimalsSeparator (public char)
It's a public property that can be assigned and retrieved. It must contain the separator symbol for decimals that we want our input
text to show when masked. If empty, no decimal separator is used in the masked text. It can be assigned through the Properties window at design time.
Default value: '.'.
Definition:
private char _decimalsSeparator = '.';
public char DecimalsSeparator
{
get { return _decimalsSeparator; }
set { _decimalsSeparator = value; }
}
DecimalPlaces (public int)
It's a public property that can be assigned and retrieved. It must contain the total places for decimal values that we want our input
text to show when masked. Minimum value is 0. It can be assigned through the Properties window at design time.
Default value: 2.
Definition:
private int _decimalPlaces = 2;
public int DecimalPlaces
{
get { return _decimalPlaces; }
set { _decimalPlaces = value; }
}
Public methods
formatText (public method) returns string
It formats the entered text with the desired specifications. Returns a string with the masked text.
Definition:
public string formatText()
{
this.WorkingText = this.Text.Replace(
(_preFix != "") ? _preFix : " ", String.Empty).Replace(
(_thousandsSeparator.ToString() != "") ?
_thousandsSeparator.ToString() : " ", String.Empty).Replace(
(_decimalsSeparator.ToString() != "") ?
_decimalsSeparator.ToString() : " ", String.Empty).Trim();
int counter = 1;
int counter2 = 0;
char[] charArray = this.WorkingText.ToCharArray();
StringBuilder str = new StringBuilder();
for (int i = charArray.Length - 1; i >= 0; i--)
{
str.Insert(0, charArray.GetValue(i));
if (this.DecimalPlaces == 0 && counter == 3)
{
counter2 = counter;
}
if (counter == this.DecimalPlaces && i > 0)
{
if (_decimalsSeparator != Char.MinValue)
str.Insert(0, _decimalsSeparator);
counter2 = counter + 3;
}
else if (counter == counter2 && i > 0)
{
if (_thousandsSeparator != Char.MinValue)
str.Insert(0, _thousandsSeparator);
counter2 = counter + 3;
}
counter = ++counter;
}
return (this._preFix != "" && str.ToString() != "") ?
_preFix + " " + str.ToString() :
(str.ToString() != "") ? str.ToString() : "";
}
Protected overridden methods
OnLostFocus (protected override method)
This method allows the currencyTextBox
to load the formatted text to the Text
property. It executes the formatText
method, then proceeds
to execute the original implementation of the OnLostFocus
method.
Definition:
protected override void OnLostFocus(EventArgs e)
{
this.Text = formatText();
base.OnLostFocus(e);
}
OnGotFocus (protected override method)
This method allows the currencyTextBox
to load the working text to the Text
property. In this state, the control is in edit mode (please refer
to the WorkingText
property definition above). After this, it proceeds to execute the original implementation of the OnGotFocus
method.
Definition:
protected override void OnGotFocus(EventArgs e)
{
this.Text = this.WorkingText;
base.OnGotFocus(e);
}
OnKeyPress (protected override method)
This method brings some validation to ensure that the values entered to the TextBox
are only numbers. After the validation, it executes the original implementation
of the OnKeyPress
method.
Definition:
protected override void OnKeyPress(KeyPressEventArgs e)
{
if (!Char.IsDigit(e.KeyChar))
{
if (!(e.KeyChar == Convert.ToChar(Keys.Back)))
e.Handled = true;
}
base.OnKeyPress(e);
}
Conclusion
There are so many characteristics that we can improve about a control like TextBox
, and one of the more important things that we can do is always search
for a way to improve it and make it more maintainable by adding reusable components like the CurrencyTextBox
. I hope it can help you, like it did for me.