Click here to Skip to main content
Click here to Skip to main content

TextBoxRegex - A Text Box with Data Validation

By , 29 Jun 2010
 
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:

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:

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)

About the Author

Marek Grzenkowicz
Poland Poland
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 4memberGrantN4 May '13 - 14:50 
Good explanation and resources. Thank you
GeneralFormatting..memberTolgahan ALBAYRAK29 Jan '09 - 4:47 
is this good formatting?
GeneralRe: Formatting..memberchopeen30 Jun '10 - 2:23 
What do you mean?
GeneralDisabled render bugmemberaread225 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 bugmemberchopeen11 Apr '07 - 9:13 
The code is updated - let me know if it works right now.
GeneralRegex for filenamesmemberpolofreak2 Apr '06 - 23:21 
does anyone know a working regex to check if the entered characters are valid characters to create a filename?
This means a regex that filters /\:*?"<>| so that I can build my filename from the entered Text.
 
thanks a lot
GeneralRe: Regex for filenamesmemberchopeen4 Apr '06 - 12:35 
http://regexlib.com/REDetails.aspx?regexp_id=85[^]
 
I didn't analyze it thoroughly, so read the comments. There are some corrections there.
GeneralRe: Regex for filenamesmemberpolofreak4 Apr '06 - 20:16 
WOW thanks a lot! I just tried it with the Regex like the following an it works great!
 
^(?!^(PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d|\..*)(\..+)?$)[^\x00-\x1f\\?*:\"><|/]+$
 
THX
GeneralConvert Text BoxesmemberDavestub10 Dec '04 - 1:52 
I would like to convert quite a few normal Text Box controls to your TextBoxRegex. Is there a simple way to do this without deleting my text boxes and re-creating them with your control?
GeneralRe: Convert Text Boxes [modified]memberchopeen10 Dec '04 - 4:15 
The first idea that comes to my mind is to replace (Crtl+H; remember to check the 'Search hidden text' option) all occurrences of:
 System.Windows.Forms.TextBox
with:
 Chopeen.TextBoxRegex
 
I created a very simple application and tested this method - it worked just fine. However, I know that it is rather primitive.

modified on Wednesday, June 30, 2010 8:24 AM

GeneralA Logic FlawmemberCubasis408 Nov '04 - 10:50 
Hey,
 
Firstly let me thank you for this excellent control, it's very reliable and easy-to-use. And I like it's color features.
 
However, while puzzling together the Regular Expression I needed, I found out that it had a logic flaw in it, the "IsTextValid" returns true if it can find a legit match "anywhere" in the text. Where it should compare matches to see if it is the complete Text, like in the following code:
<code>
            internal bool IsTextValid()
            {
               MatchCollection matches = this.patternRegex.Matches(this.Text);
               for(int i = 0;i<matches.Count;i++)
               {
                    if(matches[i].Value == this.Text)
                         return true;
               }
                  return false;
            }
</code>
 
It may contain some other cons/logic-flaws, as I didn't really spend much time tracing possible qualms with it. But it seems to work well with my current Expression.
 
~Cubasis
GeneralRe: A Logic Flaw [modified]memberchopeen9 Nov '04 - 8:11 
Can you post the settings (the properties and the text that you used for testing) you used? I will try to work this problem out.
 
And what does the property TextValidated return?

modified on Wednesday, June 30, 2010 8:25 AM

GeneralRe: A Logic FlawmemberCubasis4010 Nov '04 - 5:48 
Well, I can't post the exact Expression as i'm not at home at the moment.
 
But it worked to allow:
 
#:#[-#]
 
where:
# = 1 or more digit
[] = optional
 
So you could write: 2:12
and 2:12-13
 

But as the IsValidated method worked, I could type in:
 
2:3flksdjflkjewroiu
 
becouse it found a match at the beginning of the text (2:3).
 

I didn't try the TextValidated, but i'd guess it would return everything "2:3flksdjflkjewroiu".
 
But yeah, basicly, the IsValidated needs to make sure that the found match covers the "complete" text.
 
~Cubasis
 
Good night
GeneralRe: A Logic Flaw [modified]memberchopeen11 Nov '04 - 6:48 
Try using an expression like this:
 
  ^([0-9]+:[0-9]+[-0-9]*)$
 
Please, let me know if this helps.

modified on Wednesday, June 30, 2010 8:25 AM

GeneralRe: A Logic FlawmemberCubasis4011 Nov '04 - 14:07 
Ahhhhh, ofcourse!
 
Sorry, I did not think of using the & syntax in the Regular expression, so the problem is entirely my fault.
 
Thanks for showing me the solution.
 
~Cubasis
GeneralRe: A Logic Flaw [modified]memberchopeen12 Nov '04 - 7:15 
No problem.
 
If you have any other questions concerning TextBoxRegex, feel free to post them here.

modified on Wednesday, June 30, 2010 8:25 AM

QuestionTextBoxRegex as web control?memberscallion15 Oct '04 - 12:22 
Would it be possible to exdent this to a webcontrol? OMG | :OMG:
AnswerRe: TextBoxRegex as web control? [modified]memberchopeen17 Oct '04 - 23:39 
Good idea!
 
But I am afraid that it will take me some time, since I've never done regarding Web development in .NET. I am PHP guy.
 
But if anyone wants to do this, let me know. I will try to help as much as I can.

modified on Wednesday, June 30, 2010 8:23 AM

GeneralLooks goodmemberRobert Rohde30 Sep '04 - 5:03 
Nice work!
Just one improvement would be nice:
You are updating the color in the KeyUp event. It would look more "real time" if you would change the color in e.g. the TextChanged event.
GeneralRe: Looks good [modified]memberchopeen30 Sep '04 - 5:14 
I will check it out.

modified on Wednesday, June 30, 2010 8:23 AM

GeneralMissing referencememberSteve J Randall29 Sep '04 - 22:16 
Your project appears to be missing a reference to nunit.framework
 
Steve
GeneralRe: Missing reference [modified]memberchopeen30 Sep '04 - 0:46 
What do you mean?
 
I had no problems to compile it in Debug mode and run the tests.
 
What kind of problem are you experiencing?

modified on Wednesday, June 30, 2010 8:23 AM

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

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 30 Jun 2010
Article Copyright 2004 by Marek Grzenkowicz
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid