When you’re creating Winform applications, it could be useful if you also create your own controls. In this example I show you how to create custom control, with new custom property and event.
Let’s create a new kind of TextBox that only accepts numbers and a dot.
Create a new class in your project, name it TextBoxNumbersOnly and inherit it from TextBox class:
class TextBoxNumbersOnly : TextBox { }
Now let’s create the new property: NumbersOnly. We add some attribute to this property, so you’ll get hint in Visual Studio property window when selecting this component (don’t forget to add the System.ComponentModel using first):
class TextBoxNumbersOnly : TextBox { bool numbersOnly; [Browsable(true)] [Category("Custom Behavior")] [Description("Allows only numbers in the TextBox. If it's set to TRUE, Multiline property can be FALSE only!")] [DisplayName("NumbersOnly")] public bool NumbersOnly { get { return this.numbersOnly; } set { this.numbersOnly = value; } } }
Now rebuild your project by right-clicking on project name and selecting rebuild. After successful rebuild you’ll find your newly created control in Toolbox:
After creating the constructor of this class and placing this control onto the form, you’ll see the new property.
The constructor can be this simple one:
public TextBoxNumbersOnly() { NumbersOnly = true; }
So the default value of this new property will be ‘true’.
Let’s force this NumbersOnly property now we have it. We create a KeyPress event where we allow only numbers and (only 1) dot:
protected virtual void TextBoxNumersOnly_KeyPress(object sender, KeyPressEventArgs e) { if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) && (e.KeyChar != '.')) { e.Handled = true; } if ((e.KeyChar == '.') && ((sender as TextBox).Text.IndexOf('.') > -1))//check if it's the first '.' { e.Handled = true;//if no, ignore it } }
We have to subscribe to this event, but only when we set this property to ‘true’. Let’s modify the public NumbersOnly property:
public bool NumbersOnly { get { return this.numbersOnly; } set { this.numbersOnly = value; if (value) { this.KeyPress += new KeyPressEventHandler(TextBoxNumersOnly_KeyPress); } else { this.KeyPress -= new KeyPressEventHandler(TextBoxNumersOnly_KeyPress); } } }
What about the ‘Multiline’ property of the TextBox? It’s irrelevant when we enter only numbers, so let’s override it first:
public override bool Multiline { get { return base.Multiline; } set { if (!this.numbersOnly) base.Multiline = value; } }
then add this line after the event subscribing line in NumbersOnly public property:
base.Multiline = false;
There’s only 1 important thing. Our KeyPress event could be useless, if we enter some characters in the TextBox and then enable it’s NumbersOnly property. The text remains. Override the Text property with this simple one:
public override string Text { get { return base.Text; } set { if (!this.numbersOnly) base.Text = value; else { Decimal temp = 0; if (!Decimal.TryParse(value, out temp)) base.Text = ""; else base.Text = value; } } }
So if the TextBox has text in it and we enable the NumbersOnly property, it cannot be parsed so we clear the TextBox. If the TextBox had numbers in it before enabling our new property, we won’t clear it of course.
We can create new eventhandler too:
public event EventHandler<NumberKeyPressEventArgs> NumberPressed; protected virtual void OnNumberPressed(NumberKeyPressEventArgs e) { EventHandler<NumberKeyPressEventArgs> handler = NumberPressed; if (handler != null) { handler(this, e); } }
Of course we have to have the NumberKeyPressEventArgs class inherited from KeyEventArgs:
public class NumberKeyPressEventArgs : KeyEventArgs { private Keys myKeys; public Keys MyKeys { get { return myKeys; } } public NumberKeyPressEventArgs(Keys keyData) : base(keyData) { this.myKeys = keyData; } }
After all we’ll see ‘NumberPressed’ event in the events of the control:
And here’s the entire cs file with our 2 new classes:
using System; using System.ComponentModel; using System.Windows.Forms; namespace TextBoxOnlyNumbers { class TextBoxNumbersOnly : TextBox { bool numbersOnly; [Browsable(true)] [Category("Custom Behavior")] [Description("Allows only numbers in the TextBox. If it's set to TRUE, Multiline property can be FALSE only!")] [DisplayName("NumbersOnly")] public bool NumbersOnly { get { return this.numbersOnly; } set { this.numbersOnly = value; if (value) { this.KeyPress += new KeyPressEventHandler(TextBoxNumersOnly_KeyPress); base.Multiline = false; Decimal temp = 0; if (!Decimal.TryParse(this.Text, out temp)) this.Text = "0";//if the TextBox had not only numbers before enabling NumbersOnly property, it'll have the text of '0' } else { this.KeyPress -= new KeyPressEventHandler(TextBoxNumersOnly_KeyPress); } } } public override string Text { get { return base.Text; } set { if (!this.numbersOnly) base.Text = value; else { Decimal temp = 0; if (!Decimal.TryParse(value, out temp)) base.Text = ""; else base.Text = value; } } } public override bool Multiline { get { return base.Multiline; } set { if (!this.numbersOnly) base.Multiline = value; } } public TextBoxNumbersOnly() { NumbersOnly = true; } protected virtual void TextBoxNumersOnly_KeyPress(object sender, KeyPressEventArgs e) { if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) && (e.KeyChar != '.')) { e.Handled = true; } if ((e.KeyChar == '.') && ((sender as TextBox).Text.IndexOf('.') > -1))//check if it's the first '.' { e.Handled = true;//if no, ignore it } } public event EventHandler<NumberKeyPressEventArgs> NumberPressed; protected virtual void OnNumberPressed(NumberKeyPressEventArgs e) { EventHandler<NumberKeyPressEventArgs> handler = NumberPressed; if (handler != null) { handler(this, e); } } } public class NumberKeyPressEventArgs : KeyEventArgs { private Keys myKeys; public Keys MyKeys { get { return myKeys; } } public NumberKeyPressEventArgs(Keys keyData) : base(keyData) { this.myKeys = keyData; } } }