Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WinForms

Validate user input in Windows Forms

4.71/5 (50 votes)
26 Apr 20066 min read 3   17.1K  
You needn't write any code for control validation; just set a control's validation information at design-time and reduce maintenance workload.

Image 1

Introduction

ASP.NET provides a mechanism to validate user input. That is, before a user submit his/her page, there are several kinds of validators that validate the input. However, in WinForms, we can't get those excellent components. When we validate a text in a control, for example, there is a TextBox named "txtPassword", and it requires users to input a password text beginning with a letter and having 3-8 length numbers or letters, we must register txtPassword's Validating event, and the event method should like:

C#
private void txtPassword_Validating(object sender, CancelEventArgs e)
{
    if (string.IsNullOrEmpty(txtPassword.Text))
    {
        errorProvider1.SetError(txtPassword, "Password required!");
    }
    else if (!Regex.IsMatch(txtPassword.Text, @"[A-Za-z][A-Za-z0-9]{2,7}"))
    {
        errorProvider1.SetError(txtPassword, "Password invalid!");
    }
    else
    {
        errorProvider1.SetError(txtPassword, null);
    }
}

In the Submit button, the code should be like:

C#
private void btnOK_Click(object sender, System.EventArgs e)
{
    foreach (Control control in this.Controls)
    {
        // Set focus on control
        control.Focus();
        // Validate causes the control's Validating event to be fired,
        // if CausesValidation is True
        if (!Validate())
        {
            DialogResult = DialogResult.None;
            return;
        }
    }
}

It's really a dull assignment, and if there is a lot of controls in your form, it makes maintenance difficult. My goal is to validate controls without any code! With Validator, you drop it to a form and enter the validation rules for a TextBox or a ComboBox just like using the ToolTip component.

Background

I got the afflatus from the following article but implement a different approach. I suggest you read it:

Using the code

First, create a new Windows Forms application, and follow these steps to use the Validator component:

  1. Add assembly

    Open the "Toolbox" window, right click in the "General" tab, and click "Choose items...".

    Image 2

    If you have strong named Validator assembly and has added it to the GAC, you can choose it in the ".NET Framework components" list. Or else, in the example, click the "Browse" button and locate your Validator.dll assembly.

    Image 3

    Now, you can find it in "Toolbox".

  2. Add and configure the component

    Drag the Validator which has been added by the first step, and drop it on the form. Its property window should be like:

    Image 4

    The important properties for this component are:

    • Form - specify a form where validated controls lay onto. Validator will register its FormClosing event, validates controls, and decides whether to close the windows.
    • Mode - this enum value can been one, or combined by FocusChange and Submit. FocusChange means when validating a control fails, the focus stops on that control or is changed to the next tab index control; Submit means that validate controls while the form is closing, and prevent the form from closing when the validation fails.
    • BlinkRate, BlinkStyle, Icon, RightToLeft: same as ErrorProvider properties, please use MSDN for help.
  3. Configure the TextBoxes and their properties

    Now we will assume that there are three TextBoxes and one Submit button on the form.

    Image 5

    NameTextPropertiesFunction
    txtName  User name, required input.
    txtPassword PasswordChar = "*"Input password, begins with an alphabet and has 3-8 numbers or alphabets.
    txtRePassword PasswordChar = "*"Re-input password, same as password.
    txtSubmitSubmitDialogResult = OKSubmit and close form.

    Configure validation info for the controls. Now, configure txtRePassword for the demo: show the txtRePassword property window. You will surprisingly find an extra category, "Validation", there:

    • Type: dropdown the "Type on validator1" item and select the Required and Compare items.

      Image 6

    • RequiredMessage: input - "Please input re-password.".
    • ComparedControl: dropdown and select "txtPassword".
    • CompareOperator: dropdown and select "Equal".
    • CompareMessage: input "Re-Password not same as password".

    The extended properties should be like the following table (omit message):

    NameValidation
    txtNameType=Required
    txtPasswordType = Required|RegularExpression
    RegularExpression = ^[A-Za-Z][A-Za-z0-9]{2,7}$
    RegularExpressionOptions = None
    txtRePasswordType = Required|Compare
    ComparedControl = txtPassword
    CompareOperator = Equal
  4. Test your form

    Congratulations! You got to the point of using the Validator. Run your form, and when you enter an invalid value in the TextBox, it will show an error message. You click the "Submit" button, it will not close the window while there are still errors. For a full demo, I have got a "register" example for you, please analyse it yourself. If you have any problems, feel free to contact me.

Points of Interest

In this section, I want to say more about advanced components programming. It will be a guide to people who are interested in my Validator component and will show the key points of the Validator. Here, I will assume you that have basic components programming skills, like creating a component class, applying DefaultValue, DefaultEvent, and Browsable attributes, and so on.

  1. Extend property

    ErrorProvider, ToolTip, and Validator - these components provide a mechanism which extends controls' (or components') properties, in the property window. You will see text like "Type on validator1", which means Type property is an extended property and is provided by the validator1 control (or component). To have this amazing feature:

    • The component must implement the IExtenderProvider interface.
      C#
      public partial class Validator : Component, IExtenderProvider

      IExtenderProvider has an abstract method that must be implements (from MSDN):

      • CanExtend: Returns whether or not the provider can provide an Extender for the given object in the specified category.

      In Validator, we validate controls which allow user inputs, like ComboBox (simple, dropdown), TextBox, RichTextBox, thus, the Validator's CanExtend method is:

      C#
      public bool CanExtend(object extendee)
      {
          // Only accept TextBoxBase driver class 
          // (TextBox and RichTextBox) and ComboBox
          if (extendee is TextBoxBase || extendee is ComboBox)
          {
              return true;
          }
          else
          {
              return false;
          }
      }
    • Apply the ProvideProperty attribute and the correlated Get/Set method.

      ProviderProperty attribute shouldn't run solely, it must have the Get/Set pair methods in the component class. In Validator, I define an extended property for the control.

      C#
      [ProvideProperty("Type", typeof(Control))
      ......
      public partial class Validator : Component, IExtenderProvider

      Also, has Get/Set methods:

      C#
      public partial class Validator : Component, IExtenderProvider
      {
          DefaultValue(Itboy.Components.ValidationType.None)]
          ... ...
          public ValidationType GetType(Control control)
          {
              ... ...
          }
          
          public void SetType(Control control, ValidationType type)
          {
              ... ...
          }
      }
  2. Editor for the property window

    When you edit the ForeColor property for a TextBox in the property window, it drops down a Color Editor dialog.

    Image 7

    When you edit the Lines property for a TextBox in the property window, it shows a String Collection Editor dialog.

    Image 8

    Actually, a property window only provides a simple text input editor as default. How do Color and Lines properties do this? Using the Reflector v4.2 to disassemble the System.Drawing.Color struct in the System.Drawing.dll assembly, we find this struct that applies the Editor attribute.

    C#
    [Editor("System.Drawing.Design.ColorEditor, ..."]

    Disassemble the System.Windows.Form.TextBoxBase (TextBoxBase derives from TextBox) class in the System.Windows.Form.dll assembly, and we will find that the Lines property applies the Editor attribute.

    C#
    [Editor("System.Windows.Forms.Design.StringArrayEditor, ..."]

    The Editor attribute can be applied to either a class (struct) or a property. If class A applies the Editor attrubute, any other class can define properties of class A. Those properties will always be edited by the specified editor in the property window.

    Only those properties which apply the Editor attrubute will be edited by the specified editor; although other property types are same, they will be edited by the default simple text box.

    In the Validator project, I wrote a FlagEditor class, and it can edit the Flag enum type. Like the RegexOptions enum, you can choose the bit value set using | (logic OR), or click the "None" button to set enum value to 0.

    Image 9

    To implement the Editor attribute, the class must derive from UITypeEditor:

    C#
    public sealed partial class FlagsEditor : UITypeEditor

    and override the EditValue and GetEditStyle methods. For details, you can refer to MSDN.

    My FlagsEditor class:

    C#
    public override object EditValue(ITypeDescriptorContext context, 
           IServiceProvider provider, object value)
    {
        .....
        // Validate value is a enum type with Flags attribute.
        if (!value.GetType().IsEnum)
        {
            return value;
        }
        object[] attributes = 
          value.GetType().GetCustomAttributes(typeof(FlagsAttribute), 
          false);
        if ((attributes == null)
           || (attributes.Length == 0))
        {
            return value;
        }
    
        .....
        if (service != null)
        {
            FlagsEditorControl control = new FlagsEditorControl(value);
            service.DropDownControl(control);
    
            // Create new enum value.
            Type type = value.GetType();
            object newValue = Activator.CreateInstance(type);
            FieldInfo field = type.GetFields(BindingFlags.Public | 
                              BindingFlags.Instance)[0];
            field.SetValue(newValue, control.EditValue);
        }
        ......
    }

    First, it asserts that we can only edit the enum type with Flags attribute. Secondly, it drops down a user control which has a "None" button to set the enum value to 0, and has several check list items each of which represents one enumeration member except "None".

  3. Component Designer

    Have you noticed that, if you set the focus on a ListView control at design time, there appears a triangle button on it. When you click it, it will show a context menu.

    Image 10

    Besides, when you drop a ErrorProvider to a Form, it will automatically generate a line like:

    C#
    this.errorProvider1.ContainerControl = this;

    How does C# do that? In Validator, I apply the Design attribute:

    C#
    [Designer(typeof(Validator.ValidatorDesigner), typeof(IDesigner))]

    ValidatorDesign derives from ComponentDesign which provides an approach to above issues. ComponentDesign has a virtual property ActionLists, which returns a menu like the ListView control, and has a virtual method InitializeNewComponent telling the IDE how to generate code.

History

  • April 11th, 2006 - First version.

Thanks to

  • Michael Weinhardt, for his article in MSDN.
  • Bo Shen, who checks my article and corrects my English.

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