Bookmark and Share Share...    Subscribe to this feed Feed   About me...


Data Validation in WPF

What we want to do is a simple entry form for an e-mail address. If the user enters an invalid e-mail address, the border of the textbox gets red and the tooltip is showing the reason.

Implementing a ValidationRule (.NET 3.0 style)

In this example I am implementing an generic validation rule that takes a regular expression as validation rule. If the expression matches the data is treated as valid.

 
/// <summary>
/// Validates a text against a regular expression
/// </summary>
public class RegexValidationRule : ValidationRule
{
    private string _pattern;
    private Regex _regex;
 
    public string Pattern
    {
        get { return _pattern; }
        set
        {
            _pattern = value;
            _regex = new Regex(_pattern, RegexOptions.IgnoreCase);
        }
    }
 
    public RegexValidationRule()
    {
    }
 
    public override ValidationResult Validate(object value, CultureInfo ultureInfo)
    {
        if (value == null || !_regex.Match(value.ToString()).Success)
        {
            return new ValidationResult(false, "The value is not a valid e-mail address");
        }
        else
        {
            return new ValidationResult(true, null);
        }
    }
}
 
 

First thing I need to do is place a regular expression pattern as string to the windows resources

 
<Window.Resources>
        <sys:String x:Key="emailRegex">^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@
        [a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]
        *[a-zA-Z]$</sys:String>    
</Window.Resources>
 
 

Build a converter to convert ValidationErrors to a multi-line string

The following converter combines a list of ValidationErrors into a string. This makes the binding much easier. In many samples on the web you see the following binding expression:

{Binding RelativeSource={RelativeSource Self},Path=(Validation.Errors)[0].ErrorContent}

This expression works if there is one validation error. But if you don't have any validation errors the data binding fails. This slows down your application and causes the following message in your debug window:

System.Windows.Data Error: 16 : Cannot get ‘Item[]‘ value (type ‘ValidationError’) from ‘(Validation.Errors)’ (type ‘ReadOnlyObservableCollection`1′). BindingExpression:Path=(0).[0].ErrorContent; DataItem=’TextBox’...

The converter is both, a value converter and a markup extension. This allows you to create and use it at the same time.

 
[ValueConversion(typeof(ReadOnlyObservableCollection<ValidationError>), typeof(string))]
public class ValidationErrorsToStringConverter : MarkupExtension, IValueConverter
{
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return new ValidationErrorsToStringConverter();
    }
 
    public object Convert(object value, Type targetType, object parameter, 
        CultureInfo culture)
    {
        ReadOnlyObservableCollection<ValidationError> errors =
            value as ReadOnlyObservableCollection<ValidationError>;
 
        if (errors == null)
        {
            return string.Empty;
        }
 
        return string.Join("\n", (from e in errors 
                                  select e.ErrorContent as string).ToArray());
    }
 
    public object ConvertBack(object value, Type targetType, object parameter, 
        CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
 
 

Create an ErrorTemplate for the TextBox

Next thing is to create an error template for the text box.

 
<ControlTemplate x:Key="TextBoxErrorTemplate" TargetType="Control">
    <Grid ClipToBounds="False" >
        <Image HorizontalAlignment="Right" VerticalAlignment="Top" 
               Width="16" Height="16" Margin="0,-8,-8,0" 
               Source="{StaticResource ErrorImage}" 
               ToolTip="{Binding ElementName=adornedElement, 
                         Path=AdornedElement.(Validation.Errors), 
                         Converter={k:ValidationErrorsToStringConverter}}"/>
        <Border BorderBrush="Red" BorderThickness="1" Margin="-1">
            <AdornedElementPlaceholder Name="adornedElement" />
        </Border>
    </Grid>
</ControlTemplate>
 

The ValidationRule and the ErrorTemplate in Action

Finally we can add the validation rule to our binding expression that binds the Text property of a textbox to a EMail property of our business object.

 
<TextBox x:Name="txtEMail" Template={StaticResource TextBoxErrorTemplate}>
    <TextBox.Text>
        <Binding Path="EMail" UpdateSourceTrigger="PropertyChanged" >
            <Binding.ValidationRules>
                <local:RegexValidationRule Pattern="{StaticResource emailRegex}"/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>
 
 

How to manually force a Validation

If you want to force a data validation you can manually call UpdateSource() on the binding expression. A useful scenario could be to validate on LostFocus() even when the value is empty or to initially mark all required fields. In this case you cann call ForceValidation() in the Loaded event of the window. That is the time, when the databinding is established.

The following code shows how to get the binding expression from a property of a control.

 
private void ForceValidation()
{
  txtName.GetBindingExpression(TextBox.TextProperty).UpdateSource();    
}
 
 



 Comments on this article

Show all comments
Erin
Commented on 21.March 2009
Where is Regex defined? I get errors saying that it could not be found.

P.S. Thanks for a great site!
Erin
Commented on 21.March 2009
I figured out which namespace I needed to resolve the Regex problem (using System.Text.RegularExpressions), but I've run into a couple of issues.

First, I kept getting an error saying that "local" is an undeclared namespace. After a bit of searching online, I was able to resolve that problem by typing "xmlns:local="clr-namespace:MyProject"" at the top of my Window xaml file.

The current issue I'm unable to get past is the <Windows.Resource> part. I keep getting an error saying that "The type 'sys:String' was not found. Verify that you are not missing an assembly reference and that all referenced assemblies have been built."

I can't seem to define the emailRegex part correctly. Any ideas what I'm missing?

Thanks!
Erin
Michel
Commented on 5.May 2009
Erin, have you tried to add an xmlns like ' xmlns:sys=clr-namespace:System..' at the top of your XAML file ?
RonO
Commented on 21.May 2009
Just a note to say I had the same issue as Erin. I addressed it in the manner Michel suggested, but this leads me to another error: Could not create an instance of type 'String'. I haven't found a resolution to this particular issue. It would be helpful if the example presented were accompanied by hold project downloads or complete listings to serve as a comparison.
RonO
Commented on 21.May 2009
Now don't I feel like a dolt. I was building the application up in increments. As such, I didn't supply a value for the string until later. The error I reported above was resolved when I gave it a value.
Roma
Commented on 1.July 2009
i just wondering. let say i put Submit button, then how the button proceed with valid data ?
Philip Patrick
Commented on 5.October 2009
Thanks! Was looking for a quick guide like this :)
David
Commented on 27.October 2009
you could just use this:
ToolTip="{Binding ElementName=MyAdorner, Path=AdornedElement.(Validation.Errors).CurrentItem}"

instead of the one MS provides
Vaishali
Commented on 20.November 2009
Could not get "Source="{StaticResource ErrorImage}" " this part of the code. Can anyone help.
Murali
Commented on 12.December 2009
It would be more intresting if you could provide with more samples with screen shots
ImgErr
Commented on 8.January 2010
Cannot find resource named '{ErrorImage}'
Can someone help on this?
anon
Commented on 8.January 2010
Please provide complete code.. As a beginner, its difficult to join the dots! :)
Ceri
Commented on 15.January 2010
For those of you who can't get get this example to work...try this link http://www.switchonthecode.com/tutorials/wpf-tutorial-binding-validation-rules. It will help fill in the missing bits.
Ceri
Commented on 15.January 2010
For those of you who can't get get this example to work...try this link http://www.switchonthecode.com/tutorials/wpf-tutorial-binding-validation-rules. It will help fill in the missing bits.
Sandy
Commented on 27.January 2010
Thanks Ceri, that was a better example and with source code and solution file to understand
jd
Commented on 8.February 2010
is the tooltip supposed to open when there is an error. When I do this, the tooltip has the message but only opens when I hover the mouse over.
jd
Commented on 8.February 2010
is the tooltip supposed to open when there is an error. When I do this, the tooltip has the message but only opens when I hover the mouse over.
jd
Commented on 8.February 2010
is the tooltip supposed to open when there is an error. When I do this, the tooltip has the message but only opens when I hover the mouse over.
Mike
Commented on 26.February 2010
This is a good article but I agree with others who requested a project download... when you're new to WPF it's not obvious sometimes what goes where or what references are needed etc. Remember, not everyone's a guru!!
kap
Commented on 17.March 2010
Plz post the complete Window1.xaml content... Important things are missing.
Error
Commented on 17.March 2010
Error:
This is wrong: Template={StaticResource TextBoxErrorTemplate}>

It must be: <TextBox x:Name="txtEMail" Validation.ErrorTemplate="{StaticResource TextBoxErrorTemplate>

Now it works!
Klara
Commented on 29.March 2010
Is it possible to use DataAnnotations with xaml and if so, any chance of a short example code?
Christian...
Commented on 18.May 2010
Hello, Everyone thanks for your comment, i m looking forward to publish my new site which is on WCF it might help you please go through www.wcf.ru
Alex
Commented on 18.May 2010
OK?!?!?!, I did Hello World, worked fine, but am I missing step in between to be able to achieved this puzzle, or I am going too quick. What goes where?!!??!?
Nice web site, but you should add steps to know what to try first, second,...
GaaTy
Commented on 2.July 2010
Excellent Article. Got it working easily. Helped me alot!

Name
E-Mail (optional)
Comment
About Christian Moser