Home > Articles > Microsoft > Other Microsoft

  • Print
  • + Share This
This chapter is from the book

Validating User Input

Validate user input.

Garbage in results in garbage out. When designing an application that accepts data from the user, you must ensure that the entered data is acceptable for the application. The most relevant place to ensure the validity of data is at the time of data entry itself. You can use various techniques for validating data:

  • You can restrict the values that a field can accept by using standard controls such as combo boxes, list boxes, radio buttons, and check boxes. These allow users to select from a set of given values rather than permit free keyboard entry.

  • You can capture the user's keystrokes and analyze them for validity. Some fields may require the user to enter only alphabetic values but no numeric values or special characters; in that case, you can accept the keystrokes for alphabetic characters while rejecting others.

  • You can restrict entry in some data fields by enabling or disabling them, depending on the state of other fields.

  • You can analyze the contents of the data field as a whole and warn the user of any incorrect values when he or she attempts to leave the field or close the window.

The first technique is discussed relative to the use of various controls in Chapter 2, "Controls"; the following sections cover rest of these techniques.

Keystroke-Level Validation

When you press a key on a control, three events take place, in the following order:

  1. KeyDown

  2. KeyPress

  3. KeyUp

You can program the event handlers for these events in order to perform keystroke-level validation. You choose the event to program based on the order in which the event is fired and the information that is passed in the event argument of the event handler.

The KeyPress event happens after the KeyDown event but before the KeyUp event. Its event handler receives an argument of type KeyPressEventArgs. Table 3.4 lists the properties of KeyPressEventArgs.

Table 3.4 Important Members of the KeyPressEventArgs Class

Member

Type

Description

Handled

Property

Indicates whether the event has been handled

KeyChar

Property

Returns the character value that corresponds to the key


The KeyPress event fires only if the key that is pressed generates a character value. To handle keypresses for function keys, control keys, and cursor movement keys, you must use the KeyDown and KeyUp events.

The KeyDown and KeyUp events occur when the user presses and releases a key on the keyboard, respectively. Event handlers of these events receive an argument of KeyEventArgs type; it provides the properties listed in Table 3.5.

Table 3.5 Important Members of the KeyEventArgs Class

Member

Type

Description

Alt

Property

Returns true if the Alt key is pressed; otherwise, returns false.

Control

Property

Returns true if the Ctrl key is pressed; otherwise, returns false.

Handled

Property

Indicates whether the event has been handled.

KeyCode

Property

Returns the keyboard code for the event. Its value is one of the values specified in the Keys enumeration.

KeyData

Property

Returns the key code for the pressed key, along with modifier flags that indicate what combination of modifier keys (Ctrl, Shift, and Alt) are pressed at the same time.

KeyValue

Property

Returns the integer representation of the KeyData property.

Modifiers

Property

Returns the modifier flags that indicate what combination of modifier keys (Ctrl, Shift, and Alt) are pressed.

Shift

Property

Returns true if the Shift key is pressed; otherwise, returns false.


The KeyPreview Property

By default, only the active control receives the keystroke events. The Form object also has the KeyPress, KeyUp, and KeyDown events, but they are fired only when all the controls on the form are either hidden or disabled.

When you set the KeyPreview property of a form to true, the form receives all three events—KeyPress, KeyUp, and KeyDown—just before the active control receives these events. This allows you to set up a two-tier validation on controls. If you want to discard certain types of characters at the form level, you can set the Handled property for the event argument to true (this does not allow the event to propagate to the active control); otherwise, the events propagate to the active control. You can then use keystroke events at the control level to perform field-specific validations, such as restricting the field to only numeric digits.

Field-Level Validation

Field-level validation ensures that the value entered in the field is in accordance with the application's requirements. If it is not, you can display an error to alert the user about the problem. These are appropriate reasons to perform field-level validations:

  • When the user attempts to leave the field

  • When the content of the field changes for any reason

When the user enters and leaves a field, the events occur in the following order:

  1. Enter (Occurs when a control is entered.)

  2. GotFocus (Occurs when a control receives focus.)

  3. Leave (Occurs when focus leaves a control.)

  4. Validating (Occurs when a control is validating.)

  5. Validated (Occurs when a control is finished validating.)

  6. LostFocus (Occurs when a control looses focus.)

The Validating event is the ideal place to store the validating logic for a field. The following sections explain the use of the Validating event and the CausesValidation property for field-level validation. They also discuss the use of the ErrorProvider component to display error messages to the user.

The Validating Event

The Validating event is the ideal place for storing the field-level validation logic for a control. The event handler for validating the event receives an argument of type CancelEventArgs. Its only property, Cancel, cancels the event when it is set to true.

NOTE

The Validating Event and Sticky Forms The Validating event fires when you close a form. If inside the Validating event you set the Cancel property of the CancelEventArgs argument to true, the Validating event also cancels the close operation.

There is a workaround for this problem. Inside the Validating event, you should set the Cancel property of the CancelEventArgs argument to true if the mouse is in the form's client area. The close button is in the title bar that is outside the client area of the form. Therefore, when the user clicks the close button, the Cancel property is not set to true.

Inside the Validating event, you can write code to do the following:

  • Programmatically correct any errors or omissions made by the user.

  • Show error messages and alerts to the user so that the user can fix the problem.

Inside the Validating event, you might also want to retain the focus in the current control, thus forcing the user to fix the problem before proceeding further. To do this, you can use either of the following techniques:

  • Use the Focus() method of the control to transfer the focus back to the field.

  • Set the Cancel property of CancelEventArgs to true. This cancels the Validating event, leaving the focus in the control.

A related event, Validated, is fired just after the Validating event occurs—and it enables you to take actions after the control's contents have been validated.

The CausesValidation Property

When you use the Validating event to restrict the focus in the control by canceling the event, you must also consider that you are making the control sticky.

Consider a case in which the user is currently on a control such as a TextBox control, with incorrect data, and you are forcing the user to fix the problem before leaving the control, by setting the Cancel property of CancelEventArgs to true. When the user clicks the Help button in the toolbar to check what is wrong, nothing happens unless the user makes a correct entry. This can be an annoying situation for the user, so you want to avoid it in your applications.

The CausesValidation property comes to your rescue in such a case. The default value of the CausesValidation property for a control is true for all controls, which means that the Validating event fires for any control, requiring validation before the control in question receives the focus.

When you want a control to respond, regardless of the validation status of other controls, you should set the CausesValidation property of that control to false. For example, in the previous example, the Help button in the toolbar would be set with the CausesValidation property set to false.

The ErrorProvider Component

The ErrorProvider component in the Visual Studio .NET toolbox is useful when you're showing validation-related error messages to the user. The ErrorProvider component can set a small icon next to a field when it contains an error. When the user moves the mouse pointer over the icon, an error message pops up as a ToolTip. This is a better way of displaying error messages than the old way of using message boxes because it eliminates at least two serious problems with message boxes:

  • When you use message boxes, if you have errors on multiple controls, popping up several message boxes might annoy or scare your users.

  • After the user dismisses a message box, the error message is no longer available for reference.

Table 3.6 lists some important members of the ErrorProvider class with which you should familiarize yourself.

Table 3.6 Important Members of the ErrorProvider Class

Member

Type

Description

BlinkRate

Property

Specifies the rate at which the error icon flashes.

BlinkStyle

Property

Specifies a value that indicates when the error icon flashes.

ContainerControl

Property

Specifies the component's parent control.

GetError()

Method

Returns the error description string for the specified control.

Icon

Property

Specifies an icon to display next to a control. The icon is displayed only when an error description string has been set for the control.

SetError()

Method

Sets the error description string for the specified control.

SetIconAlignment()

Method

Sets the location at which to place an error icon with respect to the control. It has one of the ErrorIconAlignment values (BottomLeft, BottomRight, MiddleLeft, MiddleRight, TopLeft, and TopRight).

SetIconPadding()

Method

Specifies the amount of extra space to leave between the control and the error icon.


The ErrorProvider component displays an error icon next to a field, based on the error message string. The error message string is set by the SetError() method. If the error message is empty, no error icon is displayed, and the field is considered correct. Step by Step 3.5 shows how to use the ErrorProvider component.

STEP BY STEP 3.6 - Using the ErrorProvider Component and Other Validation Techniques

  1. Add a new Windows form to the project. Name it StepByStep3_6.

  2. Place three TextBox controls (txtMiles, txtGallons, and txtEfficiency) and a Button control (btnCalculate) on the form and arrange them as shown in Figure 3.11. Add Label controls as necessary.

  3. The ErrorProvider component is present in the Windows Forms tab of the Visual Studio .NET toolbox. Add an ErrorProvider component (errorProvider1) to the form. The ErrorProvider component is placed in the component tray.

  4. Double-click the form and add the following code to handle the Load event handler of the Form control:

    private void StepByStep3_6_Load(
      object sender, System.EventArgs e)
    {
      // Set the ErrorProvider's Icon
      // alignment for the TextBox controls
      errorProvider1.SetIconAlignment(
        txtMiles, ErrorIconAlignment.MiddleLeft);
      errorProvider1.SetIconAlignment(
        txtGallons, ErrorIconAlignment.MiddleLeft);

    }

  5. Attach the Validating event handlers to the TextBox controls and add the following code to handle the Validating event handler of the txtMiles and txtGallons controls:

    private void txtMiles_Validating(object sender,
      System.ComponentModel.CancelEventArgs e)
    {
      try
      {
        decimal decMiles =
          Convert.ToDecimal(txtMiles.Text);
        errorProvider1.SetError(txtMiles, "");
      }
      catch(Exception ex)
      {
        errorProvider1.SetError(txtMiles, ex.Message);
      }
    }
    
    private void txtGallons_Validating(object sender,
       System.ComponentModel.CancelEventArgs e)
    {
      try
      {
        decimal decGallons =
           Convert.ToDecimal(txtGallons.Text);
        if (decGallons > 0)
          errorProvider1.SetError(txtGallons, "");
        else
          errorProvider1.SetError(txtGallons,
           "Please enter a value > 0");
      }
      catch(Exception ex)
      {
        errorProvider1.SetError(
          txtGallons, ex.Message);
      }
    }
  6. Add the following code to the Click event handler of btnCalculate:

    private void btnCalculate_Click(
      object sender, System.EventArgs e)
    {
      // Check whether the error description is not empty
      // for either of the TextBox controls
      if (errorProvider1.GetError(txtMiles) != "" ||
        errorProvider1.GetError(txtGallons) != "")
        return;
    
      try
      {
        decimal decMiles =
          Convert.ToDecimal(txtMiles.Text);
        decimal decGallons =
          Convert.ToDecimal(txtGallons.Text);
        decimal decEfficiency = decMiles/decGallons;
        txtEfficiency.Text =
          String.Format("{0:n}", decEfficiency);
      }
      catch(Exception ex)
      {
        string msg = String.Format(
          "Message: {0}\n Stack Trace:\n {1}",
          ex.Message, ex.StackTrace);
        MessageBox.Show(msg, ex.GetType().ToString());
      }

    }

  7. Insert the Main() method to launch the form. Set the form as the startup object for the project.

  8. Run the project. Enter values for miles and gallons and click Calculate. The program calculates the mileage efficiency, as expected. When you enter an invalid value into any of the TextBox controls, the error icon starts blinking and displays the error message when the mouse is hovered over the error icon, as shown in Figure 3.11.

Figure 3.11Figure 3.11 The ErrorProvider component shows the error icon and the error message in a nonintrusive way.

Enabling Controls Based on Input

One of the useful techniques for restricting user input is selectively enabling and disabling controls. These are some common cases in which you would want to do this:

  • Your application might have a check box titled Check Here if You Want to Ship to a Different Location. Only when the user checks the check box should you allow him or her to enter values in the fields for the shipping address. Otherwise, the shipping address is the same as the billing address.

  • In a Find dialog box, you have two buttons: Find and Cancel. You want to keep the Find button disabled initially and enable it only when the user enters search text in a text box.

The Enabled property for a control is true by default. When you set it to false, the control cannot receive the focus and appears grayed out.

For a control such as TextBox, you can also use the ReadOnly property to restrict user input. One advantage of using the ReadOnly property is that the control is still able to receive focus, so you are able to scroll through any text in the control that is not initially visible. In addition, you can select and copy the text to the Clipboard, even if the ReadOnly property is true.

Other Properties for Validation

In addition to the techniques mentioned in the preceding sections, the properties described in the following sections allow you to enforce some restrictions on user input.

The CharacterCasing Property

The CharacterCasing property of the TextBox control changes the case of characters in the text box as required by the application. For example, you might want to convert all characters entered in a text box used for entering a password to lowercase so that there are no problems due to case-sensitivity.

The values of the CharacterCasing property can be set to three values: CharacterCasing.Lower, CharacterCasing.Normal (the default value), and CharacterCasing.Upper.

The MaxLength Property

The MaxLength property of a TextBox or ComboBox control specifies the maximum number of characters that the user can enter into the control. This property is handy when you want to restrict the size of some fields, such as fields for telephone numbers or zip codes. This property is useful in scenarios in which you are adding or updating records in a database with the values entered in the controls; in such a case you can use the MaxLength property to prevent the user from entering more characters than the corresponding database field can handle.

TIP

The Scope of the MaxLength Property The MaxLength property affects only the text that is entered into the control interactively by the user. Programmatically, you can set the value of the Text property to a value that is longer than the value specified by the MaxLength property.

When the MaxLength property is zero (the default), the number of characters that can be entered is limited only by the available memory.

Guided Practice Exercise 3.2

As a Windows developer for a data analysis company, you recently developed a keyword searching form for your Windows application (refer to Guided Practice Exercise 3.1). The form asks for a filename and a keyword from the user, and then it searches for the keyword in the file and displays the number of lines that contain the keyword in the results group box. The form assumes that the entered keyword is a single word. In the solution in Guided Practice Exercise 3.1, if the keyword is not a single word, the form creates and throws a custom exception for that case. Since you created that solution, you have studied field-level validation techniques and realized that for this scenario, the use of field-level validation provides a much more elegant solution.

You now want to modify the keyword searching form. Its basic functionality is still the same as in Guided Practice Exercise 3.1, but you need to incorporate a few changes in the user interface. Initially the keyword text box and the Search button are disabled; you should enable these controls as the user progresses through the application. If the keyword entered by the user is not a single word, instead of throwing an exception, you need to display the error icon with the keyword text box and set an error message. The keyword text box should not lose focus unless it has valid data.

How would you create such a form?

You should try working through this problem on your own first. If you get stuck, or if you'd like to see one possible solution, follow these steps:

  1. Add a new form to your Visual C# .NET project. Name the form GuidedPracticeExercise3_2.cs.

  2. Place and arrange the controls on the form as shown in Figure 3.8. Name the TextBox control for accepting the filename txtFileName and the Browse button btnBrowse. Set the ReadOnly property of txtFileName to true. Name the TextBox control for accepting the keyword txtKeyword and the Button control btnSearch. Set the tab order of the form in the correct order so that the user's cursor is not placed in a read-only text box when the application starts.

  3. Add an OpenFileDialog control to the form and change its name to dlgOpenFile. Add an ErrorProvider component (errorProvider1) to the form. The ErrorProvider component is placed in the component tray.

  4. Double-click the form to attach the Load event handler to the form. Add the following code to handle the Load event of the Form control:

    private void GuidedPracticeExercise3_2_Load(
      object sender, System.EventArgs e)
    {
      // Disable the keyword text box and Search button
      txtKeyword.Enabled = false;
      btnSearch.Enabled = false;
      errorProvider1.SetIconAlignment(
        txtKeyword, ErrorIconAlignment.MiddleLeft);
    }
  5. Attach TextChanged and Validating event handlers to the txtKeyword control and add the following code:

    private void txtKeyword_TextChanged(
      object sender, System.EventArgs e)
    {
      if(this.txtKeyword.Text.Length==0)
        this.btnSearch.Enabled = false;
      else
        this.btnSearch.Enabled = true;
    }
    
    private void txtKeyword_Validating(object sender,
      System.ComponentModel.CancelEventArgs e)
    {
      if(this.txtKeyword.Text.Trim().IndexOf(' ') >= 0)
      {
        errorProvider1.SetError(txtKeyword,
         "You must only specify a single word");
        txtKeyword.Focus();
        txtKeyword.Select(0, txtKeyword.Text.Length);
      }
      else
        errorProvider1.SetError(txtKeyword, "");
    }
  6. Create a method named GetKeywordFrequency() that accepts a string and returns the number of lines containing it. Add the following code to the method:

    private int GetKeywordFrequency(string path)
    {
      int count = 0;
      if (File.Exists(path))
      {
        StreamReader sr =
          new StreamReader(txtFileName.Text);
        while (sr.Peek() > -1)
          if (sr.ReadLine().IndexOf(txtKeyword.Text)
            >= 0)
            count++;
      }
      return count;
    }
  7. Add the following code to the Click event handler of btnBrowse:

    private void btnBrowse_Click(
      object sender, System.EventArgs e)
    {
      if (dlgOpenFile.ShowDialog() == DialogResult.OK)
      {
        txtFileName.Text = dlgOpenFile.FileName;
        this.txtKeyword.Enabled = true;
        this.txtKeyword.Focus();
      }
    }
  8. Add the following code to the Click event handler of btnSearch:

    private void btnSearch_Click(
      object sender, System.EventArgs e)
    {
      if (errorProvider1.GetError(txtKeyword) != "")
        return;
      try
      {
        lblResult.Text = String.Format(
         "The keyword: '{0}' was found in {1} lines",
         txtKeyword.Text,
         GetKeywordFrequency(txtFileName.Text));
      }
      catch(Exception ex)
      {
        string msg = String.Format(
          "Message:\n {0}\n\n StackTrace:\n{1}",
          ex.Message, ex.StackTrace);
        MessageBox.Show(msg, ex.GetType().ToString());
      }
    }
  9. Insert the Main() method to launch form GuidedPracticeExercise3_2.cs. Set the form as the startup object for the project.

  10. Run the project. The keyword text box and the search button are disabled. Click the Browse button and select an existing file; this enables the keyword text box. Enter the keyword to search in the file; this enables the Search button. Click the Search button. If the keyword entered is in the wrong format (for example, if it contains two words), the ErrorProvider component shows the error message and the icon.

If you have difficulty following this exercise, review the section "Validating User Input," earlier in this chapter, and then try this exercise again.

  • It a good practice to validate user input at the time of data entry. Thoroughly validated data results in consistent and correct data stored by the application.

  • When a user presses a key, three events are generated, in the following order: KeyDown, KeyPress, and KeyUp.

  • The Validating event is the ideal place for storing the field-level validation logic for a control.

  • The CausesValidation property specifies whether validation should be performed. If it is set to false, the Validating and Validated events are suppressed.

  • The ErrorProvider component in the Visual Studio .NET toolbox is used to show validation-related error messages to the user.

  • A control cannot receive the focus and appears grayed out if its Enabled property is set to false.

The .NET Framework provides fully integrated support for exception handling. In fact, it allows you to raise exceptions in one language and catch them in a program written in another language. The try block is used to enclose code that might cause exceptions. The catch block is used to handle the exceptions raised by the code in the try block, and the finally block ensures that certain code is executed, regardless of whether an exception occurs.

The FCL provides a large number of exception classes that represent most of the exceptions that a program may encounter. If you prefer to create your own custom exception class, you can do so by deriving your exception class from the ApplicationException class.

This chapter describes a variety of ways to validate user input. The Windows Forms library provides an ErrorProvider component that is used to signal errors. You can also associate custom icons and error messages with the ErrorProvider component.

  • + Share This
  • 🔖 Save To Your Account