Displaying Data Validation Messages in WPF

As you can probably tell from my last couple posts I've been working with WPF in different data scenarios. Yesterday I was playing with data validation in WPF and .NET 3.5 which is pretty slick. In this article I'll walk through how to hook up validation in your data objects using the IDataErrorInfo interface and then I'll go through a couple Validation ErrorTemplates you can use to display the validation error messages and cues to the user.

Performing Validation on Data Objects

If you're using custom business objects or LINQ to SQL classes you first need to implement the IDataErrorInfo interface in order to collect validation messages on your objects. If you are using DataSets on your WPF or Windows Forms, the DataRowView already implements this interface so you can just add validation to your DataTable partial classes and you're good to go. Just open the DataSet designer, right-click on the DataTable and select "View Code" and party on. For instance, if we have a customer DataTable we can write validation for the LastName field like so:

If you're building our own custom business objects or are using LINQ to SQL classes then it's up to you to implement the IDataErrorInfo interface yourself. I showed how to do this with LINQ to SQL classes in this post where I set it up in a base business class. Here's a "short version" example implementation for a customer LINQ to SQL class that performs the same validation on the LastName field:

Now that our data objects are validating themselves we can data bind them to a form. Setting up a simple WPF Window with some TextBoxes and binding them is easy in XAML once you get the knack for remembering the syntax ;-). The key is to make sure you specify the ValidatesOnDataErrors attribute on the Binding and set it to True. Take a look at the TextBoxes in the XAML below:

Now we can load our data and set it to the Window.DataContext in the Window_Loaded event handler. If you're using DataSets, then set up your TableAdapter query like normal and Fill the DataSet. Then set the Window's DataContext to the customer DataTable:

So if we were to run this as-is WPF would give us a default visual cue when our validation fails. The control is drawn with a red border indicating there is a problem, however no message is displayed. Oh yea, that's helpful! Prepare for your tech support phone lines to light up if you release this baby.

Specifying a Custom Validation Style

We obviously want to let the user know what needs fixing here. Let's just do something simple and display the message in a ToolTip. For now, we can just create a Style in our Window.Resources section that applies to the Textboxes on this form. The Style sets up a Trigger that sets the ToolTip property to the validation message when the Validation.HasError changes to True:

Now when we run this again, you'll see that when you hover over the TextBox the validation message is displayed in a ToolTip. Better! But this solution only displays for TextBoxes. What about the rest of our controls like CheckBoxes, ComboBoxes, etc.? And we really want to declare all this in one place for our entire application. No problem, we can stick this Style into the Application.Resources instead. We can also specify that the TargetType="Control" and then we can declare additional styles for the rest of our controls and base them on this one. Open up your Application.xaml and add this XAML to your Resources section:

We just need to specify a x:Key for the Template and then we can set the BasedOn attribute on the inherited Styles. Now all the controls in the entire application can pick up this Style.

Replacing the Entire ErrorTemplate

So far all we've done is specify a Style Trigger. The default WPF ErrorTemplate is still being utilized as we're still seeing the red border around the control. We can completely change the ErrorTemplate that is used by defining a new one here in the Application.Resources. Let's take a simple example by setting up our ErrorTemplate to display a generic message over the control. In the Style above the Trigger section (we'll leave the ToolTip mesage there) we set the Validation.ErrorTemplate property and its Value to our very own ControlTemplate.

Now when we run this again, we still get our ToolTip when we hover over the control, but now we're also overlaying the control with TextBlock we defined in our ControlTemplate. Notice that there's no more red border:

Okay a pretty lame example, I admit. The problem (besides being a sarcastic message) is that the TextBlock is really covering the control and you have to hover over the edge to get the ToolTip to display. The other problem of course is that if we start typing into the field again the message won't disappear until we tab off if it so that's pretty annoying.

Instead you can stick a DockPanel into the ControlTemplate and Dock the TextBlock to the right in order to display the text after the control (and this time let's just display an asterisk). Say you want to still have that red border around the control. We can do this by specifying a special element called AdornedElementPlaceholder in our XAML for the ErrorTemplate Setter.Value:

Much better! Of course you can use your imagination to create any kind of visual cue appropriate for your application. That's the cool thing about WPF.

Duplicating the Winforms ErrorProvider Look and Feel

For those Winforms developers out there, what if you want to duplicate the look and feel of the ErrorProvider which displays a blinking error icon? I always liked to place the red error icon inside the right-hand side of the control so I didn't have to worry about spacing issues between the controls when I was designing forms. And I actually liked how the icon would flash a few times and then stop. It's relatively easy to do this type of animation in WPF using Storyboards (and it's REALLY easy to create animations in Expression Blend so I highly recommend you have a look at that product if you're making the transition to WPF).

This time we'll create an Ellipse and set up an EventTrigger for the Loaded event to begin our animation which will simply toggle the Visibility property of the Ellipse a few times. We also want to place a TextBlock over the Ellipse whose Text is an exclamation point (the animation will run on this as well). And since I want to place these inside the right-hand side of the control by setting a negative left margin, I'm going to want to also set the ToolTips of the Ellipse and the TextBlock so that if the user hovers over the error glyph it will display the ToolTip as well.

Here's the complete XAML to enable this look and feel contained in the Application.Resources:

Now when we run our application and trigger the validation error we see an error icon that flashes 3 times (it looks a lot smoother than this image ;-))

Validating your data objects in WPF with the .NET Framework 3.5 is the same as before with WinForms using the IDataErrorInfo interface. However, WPF styles and control templates make displaying visual cues to the user extremely flexible. If you can imagine it, you can probably do it with WPF.

Quick question on new entries. If the user clicks save before any data is entered the OnValidate event within the biz layer will throw an error. How do the WPF controls get notified of the errors since no propertychanged event was fired? I am stuck at this point and would like to show the red border, etc. on each invalid field when this occurs.

Thanks,

Doug

Abel

6 Jun 2009 5:47 PM

how can return exactly at cell with error after an n validations rule´s violation??? .

I blink errorprovider in cell with error but I jump to another cell.

can yoy helpme.

Sharf

29 Jul 2009 2:12 PM

Is there way column allow only numeric? How can I do that? For ex, If I type letters in bounded textbox it should not allow. I can did this in textbox validation but I need in Dataset partial class. Can you help me please?

Hmm...! That is not exactly what I mean. Actually, I drag & drop Dataset source with DetailsView selected to Winform. So it is already bounded textbox. I need this textbox should validate from Dataset partial class when the user keypress or anyother event. Got it?

I'm trying to follow along with this article using the wpf datagrid and I am having some issues:

1. When I moved my error style to the application.xaml file I started getting

"Cannot convert the value in attribute 'ErrorTemplate' to object of type 'System.Windows.Controls.ControlTemplate'. 'System.Windows.Style' is not a valid value for property 'ErrorTemplate'. Error at object 'Microsoft.Windows.Controls.DataGridTextColumn". Any tips to track down cryptic messages like this one?

2. I am not sure how I am overriding the default ErrorTemplate? According to this article I only need to set up the style in the app.resources but not actually do a Validation.ErrorTemplate="{StaticResource myErrorTemplate}" on my control which I wish to implement this? Only setting the "ValidateOnDataError=True" will do this for me?

3. I have manually set the UpdateSourceTrigger="PropertyChanged" on my column which I am assigning the errortemplate to yet I have to tab away or hit enter to see any UI changes. In debug mode I watched my base class of items call SendPropertyChanging and SendPropertyChanged so I am not sure what I am doing wrong? I used linq-sql classes to get my dataclasses. I found another sample project from http://www.thejoyofcode.com/Reason_10._Validation.aspx and it validates as soon as I stop typing or empty the textbox. How can I get that functionality? (Again, I am using datagrid not a textbox)

I'm almost all squared away for a nice grid with in-place edits and validation if I can just get the validation to work.