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

Validating TextBox interfaces

, 24 Jul 2005
Rate this:
Please Sign up or sign in to vote.
A TextBox class with an extensible validator interface.

Sample Image

Introduction

Input controls such as the TextBox provide a validation event on exiting the control which allows a check to be performed on the contents. This is the basic mechanism. In an environment where there are a lot of controls, we need some sort of abstraction for handling validation in a consistent and scaleable manner. The method described here performs validation on both user input through the graphical interface and program input to the control. It also provides a feedback mechanism into the control so that the content may be adjusted or some visual cue, such as background color, may be used to show the valid status of the input.

Background

This scheme was originally devised for a project that had a large number of diverse checks to be performed on input data. The display was dynamically generated making it preferable to separate the graphical control from the validation.

Using the sample application

The sample project shows three text input fields. Each of these has a validator implementation attached to it. If the correct value is entered, the background stays white. If an incorrect value is entered the background goes red and a message box gives some details of the error. In this sample the user is not forced to correct the error by keeping focus on the control that is in error.

Field 1 is a regex check. In the sample, we check for a valid hex representation. Fields 2 and 3 are interrelated. The value in field 2 is a decimal value that must lie within the range specified by field 3. Field 3 specifies a range where the high value must be greater than the low value.

Description of the code

We use two interfaces here. IValidate is attached to the validator class and IDisplay to the input control. IValidate provides a Text attribute.

//
// IValidate Interface
//
public interface IValidate 
{ 
  string Text{get;set;} 
  bool IsValid{get;} 
  IDisplay TheDisplay{get;set};
}

The set operation of Text performs the validation. The validation state may be queried using the IsValid attribute. The TheDisplay attribute allows the control to pass information to the validator so that it may in turn apply visual update to the control as needed. The Text property of the textbox is overridden here so that programmatic input to the control can be intercepted and re-routed to the validator. A back-door attribute provides access to the control's Text attribute, baseText, as part of the IDisplay interface.

//
//  The IDisplay Interface
//
public interface IDisplay 
{ 
  string baseText{get;set;} 
  Control TheControl{get;} 
}

Let's take a look at the code in the validatedTextBox control starting with installation of the validator. It is installed either through a constructor or attribute.

/// <SUMMARY> 
/// Set the validator for this control 
/// </SUMMARY>
public IValidate TheValidator 
{ 
  set 
  { 
    theValidator = value; 
    theValidator.TheDisplay = this; 
    this.CausesValidation = true; 
    this.Validating += new CancelEventHandler(validatedTextBox_Validating); 
    } 
  get{return theValidator;} 
}

The public attribute TheValidator installs the validation class with the control. If no validator is installed it behaves exactly the same as a regular TextBox class. Installing a validator passes the validation class instance to the TextBox and sets up an intercept for the validation event.

/// <summary>
/// Validation event handler. Invokes the validator if present
/// </summary>
/// <PARAM name="sender"></PARAM>
/// <PARAM name="e"></PARAM>
private void validatedTextBox_Validating(object sender, CancelEventArgs e)
  {
    if (null != theValidator)
    {
      theValidator.Text = this.Text;
    }
  }

The event handler validatedTextBox_Validating passes the control's text to the validator class where it is processed. Let's take a look at the validator code now. Just a note that some of the operations are abstracted into a base class. You might well ask, why use interfaces when everything fits well into a base class? The answer to that is flexibility. In this simple example, a base class could have easily been used replacing the interface entirely. However an interface is a much more flexible approach allowing us to just bolt it onto any existing class structure, instead of imposing a structure on the implementation of our validation classes.

First a look at the base validator class. The Text attribute receives the information from the Edit control of the same name. Its job is to do the actual validation and invoke any feedback measures to the operator.

public string Text
{
  get {return textValue;}
    set
    {
      textValue = value;
      validate();
      updateDisplay();
    }
}

Next let's look at the actual implementation of a validation and what that does in relation to our scheme.

public override bool validate()
{
  Regex aRegex = new Regex(theRegex);
  IsValid      = aRegex.IsMatch(Text);
  return IsValid;
}

This validate method is in the derived class for the regex validator. What we do here is perform the nitty-gritty of our validation and set the isValid variable according to the outcome of the operation. This is illustrated as a simple operation that has no external dependencies. The range validator is slightly more complex, there is a dependency of the input text on a variable range.

Next comes the question of what to do when the input text is not what it should be. The method used here is to put up a message box and set the background color of the control. Looking again at the Text attribute we see that after validation the updateDisplay method is called.

public override void updateDisplay()
{
  base.updateDisplay ();
  if (!IsValid)
  {
    System.Windows.Forms.MessageBox.Show("Incorrect input" + 
      " for regular expression: " + theRegex);
  }
}

First the common processing is performed by calling base.updateDisplay. Next a context specific operation - show a message box giving an informative message.

public virtual void updateDisplay()
{
  if (null != TheDisplay)
  {
    TheDisplay.baseText = Text;
    if (IsValid)
    {
      TheDisplay.TheControl.BackColor = System.Drawing.Color.White;
    }
    else
    {
      TheDisplay.TheControl.BackColor = System.Drawing.Color.Salmon;
    }
  }
}

The base class method updateDisplay performs two tasks here. First of all, it sets the control's text with the validator's text. In this case that has only written back what was already there. We might want to do something else. Consider the Hex input regex box. It allows only upper case letters, so we can only input something like 0x3FEA. Now supposing we wanted to allow the user to input mixed case, like 0x3fea, but always store it internally in upper case. We could have the validator perform this operation and write it back to the control in uppers.

Conclusion

We have presented a scheme that separates the implementation of validation from the control. The validator provides feedback into the control by giving visual feedback and by modifying the text. The control itself can be used with or without a supporting validator class.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

franksbootdisk
Web Developer
United States United States
Hopeless nerd who started writing software in the early 70's and still cant give it up.

Comments and Discussions

 
Generalmost excellent... Pinmembersclark17-Aug-05 20:14 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141216.1 | Last Updated 25 Jul 2005
Article Copyright 2005 by franksbootdisk
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid