Sunday, May 5, 2013

How to use validators in WPF?

Data Validation in WPF

Here we have simple dialog box which we use to add new protocol into the system. Keeping mind that protocol is a file with extension *.HTS.

Requirements:

Now through this dialog, we will:-

1.       Capture File Path using browse button

2.       Enter Protocol name without any space or special characters.

3.       Give time estimates in seconds.

4.       Press save button to save protocol.

Now, to stop vulnerable inputs to the system, we should validate each and every input provided by end user. Let’s discuss what kind of validation we can give here.

1.       Validation for file extensions with *.hts or *.HTS

2.       Validation for space and special characters.

3.       Validation for non-negative time estimates. Min and Max time limit.

Now depending upon validation we need to provide some actions, like:

1.       Validation error message should be shown on UI.

2.       Save button should be disabled if there is any validation error.

We will address each and every validation and actions one by one.

Using ValidationRule class

WPF in .Net 3.5 and above gives ValidationRule abstract class with abstract method “Validate()”. This method gets call while validating the inputs.

Below is the example of using ValidationRule class.

 

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Windows.Controls;

using System.Text.RegularExpressions;

using System.IO;

 

namespace WPFExperiments.Validations

{

  public class InputFilePathValidationRule : ValidationRule

  {

 

    private string _pattern;

    private Regex _regex;

 

    public string Pattern

    {

      get { return _pattern; }

      set

      {

        _pattern = value;

        this._regex = new Regex(this._pattern, RegexOptions.IgnoreCase);

      }

    }

 

    public InputFilePathValidationRule()

    {

 

    }

 

    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)

    {

      ValidationResult result = new ValidationResult(true, null);

      if (value == null) return result;

 

      string input = value.ToString();

 

      try

      {

        if (!_regex.IsMatch(input))

          return new ValidationResult(false, "Wrong file name! Select only *.HTS or *.hts files");

 

        if (!File.Exists(input))

          return new ValidationResult(false, "Doesn't exist!");

      }

      catch (Exception ex)

      {

 

        throw;

      }

 

      return result;

    }

  }

}

We tried to make a generic validator for input file path and name validator using regular expression. The property Pattern is used to provide the regular expression pattern from UI. The function Validate() will validate two things.

1.       File name with specific extension.

2.       File path existence on system.

Now let’s see how we are going to use this validator in our example.

Defining Regular Expression as Static Resource

To use “InputFilePathValidationRule” we need to define regular expression that we will pass to the property of the class. We will define it as StaticResource.

 

<Window.Resources>

    <sys:String x:Key="fileRegEx">[a-zA-Z0_9].*\bhts)|([a-zA-Z0_9].*\bHTS)\b</sys:String>

  </Window.Resources>

 

For simple example, we declared this static resource in Windows.Resources which makes it local to this window only. But you can use resource dictionaries to declare it globally.

The namespace “sys” is referenced to mscorlib.dll which contains all data type classes and definitions.

We have declared two namespaces in our XAML. One namespace for the ValidationRule classes and other is for mscorlib.

 

xmlns:sys="clr-namespace:System;assembly=mscorlib"

xmlns:validator="clr-namespace:WPFExperiments.Validations"

 

Binding ValidatorRules with UI

Have a look into the highlighted section. We are validating on the input of “telerik:RadMaskedTextInput” control. We defined validation rules on the input dependency property. To bind the value with the View Model property we used “Binding” property. The “UpdateSourceTrigger” dependency property will tell WPF binding engine when to start validation. Here we have told binding engine to start validation when the control have lost the focus. Now “ValidatesOnDataErrors="True"” tells binding engine to validate this input binding.

<telerik:RadMaskedTextInput Grid.Column="1"

                            Grid.Row="0"

                            Margin="3"

                            x:Name="txtFilePath"

                            Mask=""

                            IsReadOnly="True"

                            Placeholder=""

                            AllowInvalidValues="True"

                            EmptyContent="Select protocol file."

                            VerticalAlignment="Center"

                            HorizontalAlignment="Left"

                            ext:MaskedInputExtensions.RestrictInvalidText="True"

                            Width="300">

    <telerik:RadMaskedTextInput.Value>

      <Binding Path="FileName" UpdateSourceTrigger="LostFocus" Mode="TwoWay" ValidatesOnDataErrors="True"

               ValidatesOnExceptions="True" NotifyOnValidationError="True">

        <Binding.ValidationRules>         

           <validator:InputFilePathValidationRule Pattern="{StaticResource fileRegEx}"/>

        </Binding.ValidationRules>

      </Binding>

    </telerik:RadMaskedTextInput.Value>

</telerik:RadMaskedTextInput>

 

NOTE: We have used “telerik:RadMaskedTextInput” control because this control has inbuilt error template to show validation errors. I will let you know how to create your own custom validation error template later in this post.

We have declared our custom validation rule in the “Binding.ValidationRules” section. As per dependency property name “ValidationRules” we can imagine that this section is a collection of validation rule. So we can have multiple validation rules in this section.

Right now we have only one validation rule that we defined as “InputFilePathValidationRule”. We have assigned static resource “fileRegEx” to the property “Pattern”.

So, when we run this application and give a wrong file path the validation rule throw false ValidationResult with comments.

 

[To Be Continued…]

 

DISCLAIMER ========== This e-mail may contain privileged and confidential information which is the property of Persistent Systems Ltd. It is intended only for the use of the individual or entity to which it is addressed. If you are not the intended recipient, you are not authorized to read, retain, copy, print, distribute or use this message. If you have received this communication in error, please notify the sender and delete all copies of this message. Persistent Systems Ltd. does not accept any liability for virus infected mails.

1 comment:

  1. One problem with this code. When the control is first shown no validation get applied and the error template is not shown. The user has to click in the control for validations to be applied

    ReplyDelete