Building a Self Validating Web Text Box

My goals in building this project is to build a simple web control that will inherit the basic functionality of a standard web text box, but will also wrap the validation controls into the mix. So. No more dragging’ two controls onto the page. Now I just drag out one, set the properties, and away we go. This article owes a great debt to Patick Meyer, and his article on self validating text boxes.

As a secondary goal, I wanted to finally get started on building my own web control library. As an aside, perhaps the easiest way to do this is to simply inherit from all the current web controls, then build a dll. Voilà – your own extensible code library. Not very exciting, but it is a start.

So, back to basics. When you are building controls (web or not-web) you have a couple of options. You can open a web control project, and start coding. This is great if you need to start from scratch and build some wild must-have control, but I am just trying to build a self validating text box here. Building a free form web control is a project for another day.

Most of the functionality I will need is already in the Microsoft text box class. Let’s not reinvent the wheel (See the title of my blog for more info.) We are going to inherit from the standard text box control instead. So open that web control project, and give it an appropriate name. I chose:

MyCompany.Web.UI.WebControls

This is how Microsoft sets up their controls, so I am going to run with it for now. Notice that I named the project MyCompany.Web.UI.WebControls. This will save you heartache later if you keep the namespace names the same as the project names.

Now we know we are going to inherit from text box, but the project template throws up a more generic WebControl class. Change this:

public class WebControl1 : System.Web.UI.WebControls.WebControl


To this:

public class ValidatingTextBox : System.Web.UI.WebControls.TextBox


While you are in there you can remove the Text property. Since we are inheriting from the text box, we don’t need it anymore. The text box already knows has a perfectly serviceable text property. For most inherited controls, I would also suggest removing the render control, but not for this one. We are going to use it later to emulate some of the standard validator’s functions.

Now here comes the tricky part. We want to add in validation capability. Ideally we would inherit from a validator as well. However, .Net does not support multiple inheritance (for Multi-language compatibility reasons, mainly.) But we can use interfaces, and there is an IValidator interface that will work.

So, add to the class declaration so it looks like this:

public class ValidatingTextBox : System.Web.UI.WebControls.TextBox, IValidator

The addition of an interface is like signing a contract. It is an agreement that the class will implement at the very least all the methods and properties required by the interface. In the case of the IValidator, the two properties are IsValid (surprise, surprise) and ErrorMessage. The method is (again not very surprisingly) Validate(). So I will add these right away. (If you are working with a later version of Visual Studio, It will add the stubs for you.) Along with the properties I will add the appropriate stubs

public bool IsValid {

get { return mIsValid; }

set { mIsValid = value; }

}

public string ErrorMessage {

get { return mErrorMessage; }

set { mErrorMessage = value; }

}

public virtual void Validate() {

this.IsValid = true;

}


There are the stubs – but they ain’t going to do much, as is. We need to add in the guts now. Specifically, I’d like to be able to control how the error message is rendered, I’d like to be able to turn on or off the entry required for this control, and I’d like to use a regular expression to check for validity.

Let’s do those in order:

Controlling how the error message is rendered:

If you have used the Validators at all you should be familiar with the Display property. It can be set to three values: Static, Dynamic, and None where static always shows the error message, dynamic shows it when there is an error, and none only shows the message in the validation summary. (While this is a simplification, this will be the behavior I try to duplicate.)

Let’s add an enum for these three properties, and set up a private variable of type of this enum, and set up a property to get and set this private variable:

public enum DisplayType { Static, Dynamic, None }

private DisplayType mDisplay;

public DisplayType Display {

get {return mDisplay;}

set{mDisplay = value;}

}

Next, override the render method of the control. (I told you we would use it later!) We will simply take the base class rendering and rewrite it - with one small exception. We will add the error message to the control depending on what we have chosen for the display property.

protected override void Render(HtmlTextWriter output) {

//get the rendering from the base (text box ) control

base.Render(output);

//make sure we have an error message

if (this.ErrorMessage != null && this.ErrorMessage != "" ) {

//Set up the HTML for the error message.

//If you want, you can set up properties that will allow

//the developer to change the font, but for now

//we are sticking with a red error message

string formattedMessage = " " + ErrorMessage + "";

//figure out how the user wants the message rendered

switch (Display) {

case DisplayType.Dynamic :

//check to see if the control is valid

//if it is don't display the message

if (!IsValid) {

output.Write(formattedMessage);

}

break;

case DisplayType.Static :

//always display the message

output.Write(formattedMessage);

break;

//since we do nothing here, this case is not

//really needed, but is included for completeness

case DisplayType.None:

break;

}

}

}

Turn On and Off the entry requirements for this control:

Another property! This part is actually pretty easy. This time the property will contain the field IsEntryRequired. If IsEntryRequired is true and there is nothing in the text box then the control isn’t valid. We will check this during the validation process.

public bool IsEntryRequired {

get {return mIsEntryRequired;}

set {mIsEntryRequired = value;}

}

Use a regular expression for validation:

Add in another property – this one will contain the regular expression used to evaluate the text box’s input text.

public string RegExpression {

get {return mRegExpression ;}

set {mRegExpression = value;}

}

Oh – and since we are using regular expressions don’t forget:

using System.Text;

using System.Text.RegularExpressions;

OK – we are moving right along here. Now we gotta tie it all together. We will do that using the Validate method. During this process the method will check all its settings and determine if the control is valid or not, and then update the client accordingly.  You will need to call this method from your data submit button.  This means that the validation is occurring at the server.  More on this later.

public virtual void Validate() {

//initialize IS valid to true

//we will only then check for false conditions

this.IsValid = true;

//determine if we even have any data to check

bool noData = (this.Text.Trim()==string.Empty );

//get the low hanging fruit here - see if

//the control needs an entry but doesn't have one

if (IsEntryRequired && noData) {

this.IsValid = false;

}

//only perform this next stuff if we need to

if (IsValid && !noData && (this.RegExpression != null || this.RegExpression != "")) {

Regex validCheck = new Regex(RegExpression);

this.IsValid = validCheck.IsMatch(this.Text.Trim());

}

}

To get this to work with the page (and more importantly the validation summary) you have to let the page know it has a control with validation capability.  Do this by adding it to the Page's Validator's collection when the control Initializes.  Basically the OnInit is part of the base class (Text Box) functionality, you are just extending it.

protected override void OnInit(EventArgs e) {

base.OnInit(e);

Page.Validators.Add(this);

}

protected override void OnUnload(EventArgs e) {

if (Page != null) {

Page.Validators.Remove(this);

}

base.OnUnload(e);

}

So all that being done, I want to point out a major shortcoming with this control. Every validation attempt means a round trip to the server. Ideally the control would send some JavaScript to the client when the page is initialized. With some study, I think I can figure out how to avoid this shortcoming. The link to the MSDN IValidator; documentation has some tantalizing hints on how to go about this. But I need to learn much more about JavaScript and regular expressions;, and how the validator controls interrelate with JavaScript. Looks like I will get out the reflector tool and decompile those validator controls.

You now have your own control. The next article will be on how to put it into Visual Studio. After that – more controls; specifically I want to build one that strips out Cross site scripting and / or SQL injection characters.

Complete code follows:

using System;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.ComponentModel;

using System.Text;

using System.Text.RegularExpressions;

namespace MyCompany.Web.UI.WebControls {

[DefaultProperty("ErrorMessage"),

ToolboxData("<{0}:ValidatingTextBox runat=server>")]

public class ValidatingTextBox : System.Web.UI.WebControls.TextBox {

private bool mIsValid = true;

private string mErrorMessage;

private DisplayType mDisplay;

private bool mIsEntryRequired;

private string mRegExpression;

public enum DisplayType { Static, Dynamic, None }

public string RegExpression {

get {return mRegExpression ;}

set {mRegExpression = value;}

}

public bool IsEntryRequired {

get {return mIsEntryRequired;}

set {mIsEntryRequired = value;}

}

public DisplayType Display {

get {return mDisplay;}

set{mDisplay = value;}

}

public bool IsValid {

get { return mIsValid; }

set { mIsValid = value; }

}

public string ErrorMessage {

get { return mErrorMessage; }

set { mErrorMessage = value; }

}

protected override void OnInit(EventArgs e) {

base.OnInit(e);

Page.Validators.Add(this);

}

protected override void OnUnload(EventArgs e) {

if (Page != null) {

Page.Validators.Remove(this);

}

base.OnUnload(e);

}

public virtual void Validate() {

//initialize IS valid to true

//we will only then check for false conditions

this.IsValid = true;

//determine if we even have any data to check

bool noData = (this.Text.Trim()==string.Empty );

//get the low hanging fruit here - see if

//the control needs an entry but doesn't have one

if (IsEntryRequired && noData) {

this.IsValid = false;

}

//only perform this next stuff if we need to

if (IsValid && !noData && (this.RegExpression != null || this.RegExpression != "")) {

Regex validCheck = new Regex(RegExpression);

this.IsValid = validCheck.IsMatch(this.Text.Trim());

}

}

protected override void Render(HtmlTextWriter output) {

//get the rendering from the base (text box ) control

base.Render(output);

//make sure we have an error message

if (this.ErrorMessage != null && this.ErrorMessage != "" ) {

//Set up the HTML for the error message.

//If you want, you can set up properties that will allow

//the developer to change the font, but for now

//we are sticking with a red error message

string formattedMessage = " " + ErrorMessage + "";

//figure out how the user wants the message rendered

switch (Display) {

case DisplayType.Dynamic :

//check to see if the control is valid

//if it is don't display the message

if (!IsValid) {

output.Write(formattedMessage);

}

break;

case DisplayType.Static :

//always display the message

output.Write(formattedMessage);

break;

//since we do nothing here, this case is not

//really needed, but is included for completeness

case DisplayType.None:

break;

}

}

}

}

}

Comments

# re: Building a Self Validating Web Text Box
Gravatar When you build the control this way you have to reproduce a lot of the functionality already built in to the existing controls by stubbing out and coding the interfaces. You are basically creating a composite control. Is there a way to do this by creating a full custom control that's just a wrapper around a textbox control and a regular expression validator control?

Seems like it would be easy to do but I couldn't find any examples of it.

Here's some pseudo code...

namespace WebControlLibrary1
{
[DefaultProperty("Text")]
[ToolboxData("<{0}:RegExTxtBox runat=server></{0}:RegExTxtBox>")]
public class RegExTxtBox : WebControl
{
public TextBox txtBox = new TextBox();
public RegularExpressionValidator RegExValidator = new RegularExpressionValidator();
...


Here the developer gets full access to the controls inner textbox and regular expression since they're public - but it looks like no one codes wrappers like this - they are all composite controls using inheritance/interfaces. I tried to create a sample based on the above but I got errors about the Regular Expression control being set to 'null'. Odd since the constructor sets it to new. Anyway, any ideas you have would be appreciated.

-Brian
Left by Brian on 8/29/2005 10:23 AM
# re: Building a Self Validating Web Text Box
Gravatar I did consider this approach as well, mainly for the same reasons that you did, and one more reason. I was considering adding a label to the control, so it came prelabeled with the data entry prompt.

In the overall scheme of things, I didn't go down that path because I don't like the validators in dotNet. I plan on extending this control to add in many different validation capabilities. Already the control can check to see if an entry is required as well as apply a regular expression. It reamains (in my mind) a lot more extensible and compact than if we added all the validators to a generic control as you describe above. Does that logic hold water?

Still, there is a place for composite controls. I come back to label control being part of a text box control. So I guess the next step is for me to try adding a label to the validator, and see how far I get. Thanks Brian! ;-0
Left by JT on 8/29/2005 12:00 PM
# re: Building a Self Validating Web Text Box
Gravatar is it possible to create this object on the fly and assign it to a dynamically named and created text box?

example:

Namespace.ValidatingTextBox vtb = null;
vtb = new Namespace.ValidatingTextBox();

vtb.ID = "vtb" + cel.UID;
vtb.ErrorMessage = "(required)";
vtb.Display = Namespace.ValidatingTextBox.DisplayType.Dynamic;
vtb.IsEntryRequired = true;

etc...

how would you assign to the control to validate if this was the case?

any help would be great.

Left by Kevin Hansen on 12/28/2006 4:21 PM
# re: Building a Self Validating Web Text Box
Gravatar forget about what i wrote on the control to validate, it is self contained.

i would love some feedback about creating the fly though...

thank you!
Left by Kevin Hansen on 12/28/2006 4:27 PM
# re: Building a Self Validating Web Text Box
Gravatar The next article will be on how to put it into Visual Studio. After that – more controls; specifically I want to build one that strips out Cross site scripting and / or SQL injection characters.
Left by Prakash Koshti on 4/18/2007 6:41 AM
# re: Building a Self Validating Web Text Box
Gravatar Any body has any luck with Group Validation? I can't seem to be able to build a composite control with a validation group property.
Left by tumay on 5/11/2007 7:55 PM

Leave Your Comment

Title*
Name*
Email (never displayed)
 (will show your gravatar)
Url
Comment*

 

Preview Your Comment.