TextBoxRegex is a user control that inherits from a regular
System.Windows.Forms.TextBox). It allows to check data entered by the user against any pattern. The pattern can be chosen from a set of predefined patterns (like 'small letters', 'capital letters', etc.) as well as specified in the form of wildcard or
It's been about four months since I started learning C#. Some time ago, I decided that it's high time to check how much I learned. I also wanted to find out how TDD (Test-Driven Development) really works, since only reading about it didn't convince me about its usefulness. And I heard of NDoc and it seemed like a great idea. And finally, last but not least, I wanted to write my first CodeProject article. As you can see, I was going to kill many birds with only one stone.
At the time all this thoughts were going through my head, I finished reading a bonus chapter from Platt's 'Introducing Microsoft .NET' (see the references), the one about Windows Forms controls. I've never written a control before, so I decided to finally give it a try. I used Platt's idea of text box checking entered data, but I went much further than he did in his example.
While developing this project, I was reading another .NET book - 'Extreme Programming Adventures in C#' by Ron Jeffries. I was using unit tests throughout the whole development process and you will find these tests in the source code, but neither this article nor the tests are meant to be a TDD tutorial. Some of the tests should be stronger, sometimes there aren't enough of them. I know that. But, as I mentioned, this project was meant, among other things, to be my TDD training ground.
Compiling the Sources
TextBoxRegex uses NUnit tests and as a result it references nunit.framework.dll file. I used
#endif directives to exclude unit test classes from release build. However, if you want to compile the code in debug mode, you will either need to change the nunit.framework.dll reference to point to your location of this file (if you don't have it, see the software section for NUnit links) or remove this reference completely along with all test classes (the appropriate files are located under Tests folder).
Using the Code - Basics
I will start with describing the easiest way to use
- Open a new Windows Application project. You should see an empty Form loaded in design mode.
- To add the control to the Toolbox, right-click on it, on the tab where you want the control to appear.
- Choose Add/Remove Items... option from the context menu.
- In the Customize Toolbox window, click the Browse button and navigate to the folder where you placed Chopeen.TextBoxRegex.dll.
- Open it and click OK to close the Customize Toolbox window. There should be a new control on the tab.
- Drag the
TextBoxRegex control onto the tab.
- That's it! Hit F5 - if you did everything right (and have the same keyboard mapping scheme as I do), the project will compile and run.
Of course, this project is not very useful - no matter what you type, the text box always turns pink - this indicates that your input does not match the pattern. But there isn't much more work to do, before the project turns into something much more interesting.
Let's take a look at the code generated by Visual Studio. I cut and pasted lines that concern
TextBoxRegex control below:
private Chopeen.TextBoxRegex textBoxRegex1;
this.textBoxRegex1 = new Chopeen.TextBoxRegex();
this.textBoxRegex1.Location = new System.Drawing.Point(176, 80);
this.textBoxRegex1.Name = "textBoxRegex1";
this.textBoxRegex1.TabIndex = 0;
this.textBoxRegex1.Text = "textBoxRegex1";
this.textBoxRegex1.BackColor = System.Drawing.SystemColors.Window;
this.textBoxRegex1.InvalidTextBackColor = System.Drawing.Color.LightPink;
this.textBoxRegex1.Pattern = Chopeen.TextBoxRegex.Patterns.None;
this.textBoxRegex1.PatternString = "";
this.textBoxRegex1.UseColors = true;
this.textBoxRegex1.UseInvalidTextException = true;
this.textBoxRegex1.ValidTextBackColor = System.Drawing.Color.LightGreen;
There are four blocks of code. The most important one for you is the third one. There are six properties that you can set and that determine the way
TextBoxRegex control works. All of them are described in detail in the documentation - you can download it in the form of a CHM help file.
You can also download a demo application and check everything experimentally. I added a property grid to the form and all the additional properties are grouped under a single category (Regex), so just run TextBoxRegexDemo.exe, expand the last group of properties, change their values, and see what happens.
Using the Code - Going Further
Enough about the easy stuff. Let's talk about something a little bit more advanced now.
One of the problems I encountered whilst developing
TextBoxRegex was how to tell the application whether the text that it is reading from the control is valid or not.
The first idea was to create a method - let's call it
IsValid() - returning a boolean value indicating whether user's input matches the chosen pattern. It would be the developer's duty to remember to run
IsValid() before reading the text from the control to check if there is a match. But I didn't like this idea, because the developer would face a necessity of building an additional logic every time he wanted to use
Then, I wanted to override the
Text property. But I realized that this way I would break the Rule of Least Astonishment. When there is a text box, enhanced or not, what do you expect to get when you try to read its
Text property? So my second idea was even worse, wasn't it?
And at last, a third idea came to my mind. I implemented an additional property -
TextValidated. As long as the control's text is valid, this property behaves exactly like
But when the text doesn't match the chosen pattern, an attempt to read the value of
TextValidated property either throws an
InvalidTextException or returns an empty string - that depends on the value of
UseInvalidTextException property. It is set to
true by default, but change its value to
false, if you prefer not to use exceptions.
Below, you can see an example of using
TextValidated property in a
textBoxRegex1.UseInvalidTextException = true;
MessageBox.Show("You entered" +
textBoxRegex1.TextValidated + "and you were right.");
catch (Chopeen.InvalidTextException ex)
MessageBox.Show("You were wrong.");
What Did I Learn?
David Platt says in his book that 'ActiveX controls were difficult to write because the operating system didn't supply any infrastructure for them; you had to write every bit of it yourself. I wrote one in raw C++ once, just for the sheer pain of it, and I'd rather have a root canal without anaesthesia than do it again'. I don't know (and I don't want to know) how it feels to have a root canal, but creating a .NET Windows control wasn't like a visit to the dentist in any way. Even though I have never written a control before.
When I first heard about TDD from Peter Provost's article (see the references), I was skeptical. Really skeptical. But it didn't take more than a month to turn my skepticism into enthusiasm. I admit that writing unit tests requires some additional work, but isn't it better to spend a few more minutes writing more code than hours debugging? And what's even more important - once you have created the tests, you can use them many times instead of manually checking your application after every change you made.
Thanks to this project, I also got to know the power of code refactoring. I always knew that it is important to keep the code as clean as possible, but until now, there was always this fear that the application would suddenly break after I had changed something, and I wouldn't know why. So I usually refrained from refactoring. Unit tests solve this problem. Write good, strong tests and then you can refactor as much as you want - the tests are always there to tell you when something goes wrong.
- Marc Clifton, jdunlap, 'What Is Extreme Programming?', The Code Project, 2003
- Ron Jeffries, 'Extreme Programming Adventures in C#', Microsoft Press, 2004
- James W. Newkirk and Alexei A. Vorontsov, 'Test-Driven Development in Microsoft .NET', Microsoft Press, 2004
- David S. Platt, 'Introducing Microsoft .NET, 3rd Edition', Microsoft Press, 2003
- Peter Provost, 'Test-Driven Development in .NET', The Code Project, 2003
- Sami Vaaraniemi, 'The benefits of automated unit testing', The Code Project, 2003
Software used to create TextBoxRegex
- 30th September, 2004 - Initial revision
- 6th April, 2007 - Fixed problem with rendering disabled
- 30th June, 2010 - Updated source files