Bindings are a major part of WPF, and a big part of what makes it quick to create user interfaces in. They can be a little wordy and hard to debug sometimes, but overall they are extremely useful. Hopefully, after today's tutorial, you will find them even more useful - because today we are going to talk about building validation rules right into your bindings. Yup, you heard right - bindings in WPF have built in support for validation, and a number of the common controls have built in ways for displaying validation errors.
Today we are going to build a simple little WPF application that has a
TextBox in which the user is supposed to enter an IP Address (a v4
address - I was lazy and didn't want to write a validator for ipv6 as
well :P). Below you can see a screenshot of the the app in action:


So the first thing that we need to do to add validation to a binding is
to create a validation rule. To do this, you have to create a class that
derives from
ValidationRule
and implements the abstract method Validate. There is actually only
one validation rule built into the .NET framework, the
ExceptionValidationRule,
so in most cases you will probably be writing the rules yourself.
Below you can see the code for our rule, the IPv4ValidationRule:
using System;
using System.Globalization;
using System.Windows.Controls;
namespace SOTCBindingValidation
{
public class IPv4ValidationRule : ValidationRule
{
public override ValidationResult Validate(object value,
CultureInfo cultureInfo)
{
var str = value as string;
if (String.IsNullOrEmpty(str))
{
return new ValidationResult(false,
"Please enter an IP Address.");
}
var parts = str.Split('.');
if (parts.Length != 4)
{
return new ValidationResult(false,
"IP Address should be four octets, seperated by decimals.");
}
foreach (var p in parts)
{
int intPart;
if (!int.TryParse(p, NumberStyles.Integer,
cultureInfo.NumberFormat, out intPart))
{
return new ValidationResult(false,
"Each octet of an IP Address should be a number.");
}
if (intPart < 0 || intPart > 255)
{
return new ValidationResult(false,
"Each octet of an IP Address should be between 0 and 255.");
}
}
return new ValidationResult(true, null);
}
}
}
Before you comment on it, yes I know that you can check if a string is an IP Address by using the IPAddress.Parse method. For this example, though, using that wasn't nearly as interesting - plus, unlike this validation rule, it doesn't give very informative errors as to why the given string does not parse as an IP address.
Giving informative errors are one of the reasons to use validation rules
- you get to send back information about the rule failure, instead of
just a true/false. The Validate method always returns a
ValidationResult,
which is made up of two main parts - a boolean for if the rule
passed/didn't pass, and an object holding extra information about the
error. In our case here, that object is always an error string that we
are later going to display to the user.
Ok, now that we have a validation rule, how do we use it? Below you can see the C# and XAML code for the main window of our application:
using System.Windows;
namespace SOTCBindingValidation
{
public partial class Window1 : Window
{
public static readonly DependencyProperty IPAddressProperty =
DependencyProperty.Register("IPAddress", typeof(string),
typeof(Window1), new UIPropertyMetadata("1.1.1.1"));
public string IPAddress
{
get { return (string)GetValue(IPAddressProperty); }
set { SetValue(IPAddressProperty, value); }
}
public Window1()
{ InitializeComponent(); }
}
}
Thankyou for such a detailed explaination. You made my day and I can go in the meeting confident.
Could you please explain me why does the code not work for a WPF Browser Application ???
I just tried it on a WPF browser application (XBAP), at first i thought that because of that the code would not work as expected; however it did work, the validations are performed at the right time, so i can tell you the fact that it's a browser application is not detrimental to the validation (at least in this approach).
Be sure not to miss some elements in the XAML code, such as
(1st line - i didn't see it at first and the validation did not work) and the
attribute in the
tag.
I encountered the same problem. Thank you.
My email address is anubhav0by0@gmail.com
Great thanks for your tutorial, the most comprehensive I've seen. I just have a little problem : when i switch to .NET Framework 4, the TextBlock error dont change. Why?
Hi. Thanks for the tutorial. I wanted to do this on my Autocompleteboxes from the WPF Toolkit. However it doesn't seem to work. Doesn't display the errors. I just changed to this:
Am I missing something or is it just not possible with those Autocompleteboxes?
Best regards =o)
Could you please explain me why does the code not work for a RowDetailsTemplatein Datagrid ???
Yes, finally a validation example that I can understand and that works! Thank you!
However, I've noticed a strange behaviour when the error cause changes without being okay in between. This doesn't cause the error reason to change. An example using the unmodified application above: Remove the last 1, should give the error 'Each octet of an IP Address should be a number.' Remove the (now) last dot. That should give the error 'IP adress should be four octets, separated by decimals'. However, the same error as before still remains. (This is the first occurance of this problem) Now type in 234, so that the full text is "1.1.1234". This should also trigger the four octet error, but doesn't. Finally, type in .1, so that the full text is "1.1.1234.1". It still gives the each octet error as first, however, this is certainly not the correct error!
For some reason, the binding doesn't update if there is still an error, but a different one. Does anyone know a workaround for this?
@Steve: I got the same error. Every time an error is shown a new error is not shown, because ErrorsToMessageConverter.Convert() is not called if there is more than one error in the list Validation.Errors.
A Workaround could be this: Replace the body of ErrorsToMessageConverter.Convert() with this:
and change the path of the Binding from
to
How to invoke that validation(like,will it invoke after button click?? or in textchangedenvent??)
very bad
not working in VS2010...Please help...
Thank you SOOO MUCH!!!! I was looking for an explanation on how to do this but i couldnt find any.... till i found this post. ThAnKs!
after entering the data in first part(where length=3)the focus should be in the nextpart.
thank you, this article is definitly awsome
Many thanks for the code. It works in VS2010 as long as the target framework=3.5.
Could I just ask you to explain this part please?
public partial class Window1 : Window { public static readonly DependencyProperty IPAddressProperty = DependencyProperty.Register("IPAddress", typeof(string), typeof(Window1), new UIPropertyMetadata("1.1.1.1"));
public string IPAddress { get { return (string)GetValue(IPAddressProperty); } set { SetValue(IPAddressProperty, value); } }
EXCELLENT TUTORIAL !!!!
I have a question though. Suppose I have a custom control that I've written when allows specification of MinVal and MaxVal and in my validator, I want to enforce min and max values. How do I pass them into my validator? Is there a way to validate against MinVal and MaxVal?
Not working in VS2010 with FW3.5 or FW4.0
XAML code
Thank You!!!