Following on from my last
post, I decided to give validation in WPF a go, with the added limitation that I could only use .NET 3.0 as we have a customer that has an n-1 policy and thus we are stuck with .NET 3.0 with this customer, but I digress. The application has a few textboxes and their content needs to be validated. There are two types of validation needed:
For the first one, a Regular Expression will be used and for the second one, type checking will be used, in other words, any non-integer value will trigger a validation error. A class called,
Parameters, that implements the INotifyPropertyChanged, is used to hold all the textbox values. This is the class definition:
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.ComponentModel;
5 using System.Windows.Controls;
6 using System.Globalization;
7 using System.Text.RegularExpressions;
8
9 namespace ConfigurationTool
10 {
11 public class Parameters : INotifyPropertyChanged
12 {
13 public event PropertyChangedEventHandler PropertyChanged;
14
15 string starttime;
16 int retryinterval;
17 int callretention;
18 int nofservers;
19 int threadsperserver;
20
21 public Parameters() { }
22
23 public string startTime
24 {
25 get { return starttime; }
26 set
27 {
28 starttime = value;
29 OnPropertyChanged("startTime");
30 }
31 }
32
33 public int retryInterval
34 {
35 get { return retryinterval; }
36 set
37 {
38 retryinterval = value;
39 OnPropertyChanged("retryInterval");
40 }
41 }
42
43 public int callRetention
44 {
45 get { return callretention; }
46 set
47 {
48 callretention= value;
49 OnPropertyChanged("callRetention");
50 }
51 }
52
53 public int nofServers
54 {
55 get { return nofservers; }
56 set
57 {
58 nofservers = value;
59 OnPropertyChanged("nofServers");
60 }
61 }
62
63 public int threadsperServers
64 {
65 get { return threadsperserver; }
66 set
67 {
68 threadsperserver = value;
69 OnPropertyChanged("threadsperServers");
70 }
71 }
72
73
74 protected void OnPropertyChanged(string name)
75 {
76
77 PropertyChangedEventHandler handler = PropertyChanged;
78
79 if (handler != null)
80 {
81
82 handler(this, new PropertyChangedEventArgs(name));
83
84 }
85
86 }
87
88
89 }
90
91 }
Note that starttime is a string, I guess TimeSpan object could have used to perhaps used type checking but I've just thought about it now, while writing this up.
In order to do the regex validation, the following class is used (thanks to
stackoverflow).
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Windows.Controls;
5 using System.Globalization;
6 using System.Text.RegularExpressions;
7
8 namespace ConfigurationTool
9 {
10 class RegexValidator : ValidationRule
11 {
12 string pattern;
13 string errormessage;
14 Regex regex;
15
16 public string Pattern
17 {
18 get { return pattern; }
19 set
20 {
21 pattern = value;
22 regex = new Regex(pattern, RegexOptions.IgnoreCase);
23 }
24 }
25
26 public string errorMessage
27 {
28 get { return errormessage; }
29 set
30 {
31 errormessage= value;
32 }
33 }
34
35 public RegexValidator()
36 {
37
38 }
39
40 public override ValidationResult Validate(object value, CultureInfo cultureInfo)
41 {
42 try
43 {
44 if (regex != null)
45 {
46 if (!regex.IsMatch(value.ToString()))
47 {
48 throw new FormatException();
49 }
50 else
51 {
52 return ValidationResult.ValidResult;
53 }
54 }
55
56 return new ValidationResult(false, errorMessage);
57 }
58 catch (FormatException)
59 {
60 return new ValidationResult(false, errorMessage);
61 }
62
63 }
64 }
65 }
Using this class any regular expression can be validated. All that is required is to hook it up in the xaml to a property and it will be validated. At any rate, below is the (edited) xaml for this application, with an example of using regular expression validation:
1 <Window x:Class="ConfigurationTool.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:sys="clr-namespace:System;assembly=mscorlib"
5 xmlns:u="clr-namespace:ConfigurationTool"
6 Title="Configuration Tool" Height="465" Width="565" Icon="/ConfigurationTool;component/Images/maint.ico">
7
8 <Window.Resources>
9 <u:Parameters x:Key="Pams"/>
10 </Window.Resources>
11
12 <Grid>
13 <TextBox Height="23" HorizontalAlignment="Left" Margin="371,72,0,0" Name="RunningTimetextBox" VerticalAlignment="Top" Width="144">
14 <TextBox.Text>
15 <Binding Path="startTime" UpdateSourceTrigger="PropertyChanged" Source="{StaticResource Pams}">
16 <Binding.ValidationRules>
17 <u:RegexValidator Pattern="^([0-1][0-9]|2[0-3]):[0-5][0-9]$" errorMessage="Enter a Valid Time"/>
18 </Binding.ValidationRules>
19 </Binding>
20 </TextBox.Text>
21 </TextBox>
22 <Label Content="Retry Interval (in minutes)" Height="28" HorizontalAlignment="Left" Margin="26,102,0,0" Name="label4" VerticalAlignment="Top" />
23 <TextBox Height="23" HorizontalAlignment="Left" Margin="371,101,0,0" Name="RetryIntervaltextBox" VerticalAlignment="Top" Width="144" >
24 <TextBox.Text>
25 <Binding Path="retryInterval" UpdateSourceTrigger="PropertyChanged" Source="{StaticResource Pams}">
26 <Binding.ValidationRules>
27 <ExceptionValidationRule/>
28 </Binding.ValidationRules>
29 </Binding>
30 </TextBox.Text>
31 </TextBox>
32 </Grid>
33 </Window>
Things to note with the xaml are:
- Windows resources defines the parameters class
- This class is hooked up to all textboxes via Source attribute
- The regex validation class is also hooked up to any textbox as needed.
We can compare the above with a sample code used to validate a textbox in a winforms application:
1 private void RunningTimetextBox_Validating(object sender, CancelEventArgs e)
2 {
3 try
4 {
5 if (!RunningTimetextBox.Text.Trim().Equals(string.Empty))
6 {
7 if (!Regex.IsMatch(RunningTimetextBox.Text.Trim(), Constants.timeRegex))
8 {
9 e.Cancel = true;
10
11 MessageBox.Show(Constants.errValMsg, "Error", MessageBoxButtons.OK);
12 }
13 }
14
15 }
16 catch (Exception ex)
17 {
18 MessageBox.Show(string.Format(Constants.errMsg, ex.ToString()), "Error", MessageBoxButtons.OK);
19 }
20
21 }
The code is from a similar application and while not perfect it takes about one minute to write, yes it might not be as pretty as WPF, but prettification is hardly at the top of the list for most enterprise applications. It's a nice to have not a killer feature.