Click here to Skip to main content
15,860,943 members
Articles / Programming Languages / C#

TextBoxRegex - A Text Box with Data Validation

Rate me:
Please Sign up or sign in to vote.
4.46/5 (13 votes)
29 Jun 2010CPOL7 min read 145.5K   1.8K   122   22
An enhanced text box control with powerful data validation capabilities
Sample Image - textboxregex.png

Abstract

TextBoxRegex is a user control that inherits from a regular TextBox (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 Regex (System.Text.RegularExpressions.Regex) string.

Introduction

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 #if ... #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 TextBoxRegex control.

  1. Open a new Windows Application project. You should see an empty Form loaded in design mode.
  2. To add the control to the Toolbox, right-click on it, on the tab where you want the control to appear.
  3. Choose Add/Remove Items... option from the context menu.
  4. In the Customize Toolbox window, click the Browse button and navigate to the folder where you placed Chopeen.TextBoxRegex.dll.
  5. Open it and click OK to close the Customize Toolbox window. There should be a new control on the tab.
  6. Drag the TextBoxRegex control onto the tab.
  7. 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:

C#
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;

this.Controls.Add(this.textBoxRegex1);

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 TextBoxRegex control.

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 Text.

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 try-catch block:

C#
textBoxRegex1.UseInvalidTextException = true;

try
{   // there is a match
    MessageBox.Show("You entered" + 
      textBoxRegex1.TextValidated + "and you were right.");
}
catch (Chopeen.InvalidTextException ex)
{   // there is no match
    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.

References

  • 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

Links

Software used to create TextBoxRegex

History

  • 30th September, 2004 - Initial revision
  • 6th April, 2007 - Fixed problem with rendering disabled TextBoxRegex control
  • 30th June, 2010 - Updated source files

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Poland Poland
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 4 Pin
GrantN4-May-13 14:50
GrantN4-May-13 14:50 
GeneralFormatting.. Pin
Tolgahan ALBAYRAK29-Jan-09 4:47
Tolgahan ALBAYRAK29-Jan-09 4:47 
GeneralRe: Formatting.. Pin
Marek Grzenkowicz30-Jun-10 2:23
Marek Grzenkowicz30-Jun-10 2:23 
GeneralDisabled render bug Pin
aread225-Apr-07 19:31
aread225-Apr-07 19:31 
Hello,

Thank you for this wonderful control! one thing though, when I try textBoxRegex1.Enabled = false it doesn't change
the appearance of the textbox...it disabled it but it still appears like it is active (the textbox is still white, not gray).

- Alan
GeneralRe: Disabled render bug Pin
Marek Grzenkowicz11-Apr-07 9:13
Marek Grzenkowicz11-Apr-07 9:13 
GeneralRegex for filenames Pin
polofreak2-Apr-06 23:21
polofreak2-Apr-06 23:21 
GeneralRe: Regex for filenames Pin
Marek Grzenkowicz4-Apr-06 12:35
Marek Grzenkowicz4-Apr-06 12:35 
GeneralRe: Regex for filenames Pin
polofreak4-Apr-06 20:16
polofreak4-Apr-06 20:16 
GeneralConvert Text Boxes Pin
Davestub10-Dec-04 1:52
Davestub10-Dec-04 1:52 
GeneralRe: Convert Text Boxes [modified] Pin
Marek Grzenkowicz10-Dec-04 4:15
Marek Grzenkowicz10-Dec-04 4:15 
GeneralA Logic Flaw Pin
Cubasis408-Nov-04 10:50
Cubasis408-Nov-04 10:50 
GeneralRe: A Logic Flaw [modified] Pin
Marek Grzenkowicz9-Nov-04 8:11
Marek Grzenkowicz9-Nov-04 8:11 
GeneralRe: A Logic Flaw Pin
Cubasis4010-Nov-04 5:48
Cubasis4010-Nov-04 5:48 
GeneralRe: A Logic Flaw [modified] Pin
Marek Grzenkowicz11-Nov-04 6:48
Marek Grzenkowicz11-Nov-04 6:48 
GeneralRe: A Logic Flaw Pin
Cubasis4011-Nov-04 14:07
Cubasis4011-Nov-04 14:07 
GeneralRe: A Logic Flaw [modified] Pin
Marek Grzenkowicz12-Nov-04 7:15
Marek Grzenkowicz12-Nov-04 7:15 
QuestionTextBoxRegex as web control? Pin
scallion15-Oct-04 12:22
scallion15-Oct-04 12:22 
AnswerRe: TextBoxRegex as web control? [modified] Pin
Marek Grzenkowicz17-Oct-04 23:39
Marek Grzenkowicz17-Oct-04 23:39 
GeneralLooks good Pin
Robert Rohde30-Sep-04 5:03
Robert Rohde30-Sep-04 5:03 
GeneralRe: Looks good [modified] Pin
Marek Grzenkowicz30-Sep-04 5:14
Marek Grzenkowicz30-Sep-04 5:14 
GeneralMissing reference Pin
Steve J Randall29-Sep-04 22:16
Steve J Randall29-Sep-04 22:16 
GeneralRe: Missing reference [modified] Pin
Marek Grzenkowicz30-Sep-04 0:46
Marek Grzenkowicz30-Sep-04 0:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.