This is the next sample in the WPF Sample Applications Series. The purpose of the Sample Series is to provide concise code solutions for specific programming tasks. This sample provides a brief description of the problem, the solution and full source code.
Validating user input in a software application is essential. We have all heard the phrase, “garbage in, garbage out.” It’s the developers responsibility to ensure that their software enforces validation rules and does not allow invalid data to be processed or persisted. The software should report data entry rule violations or errors in a nonintrusive, yet informative manner so that the user can get their work accomplished without having to respond to modal dialog boxes each time a rule is broken or an entry error occurs.
This sample is on the handling and reporting of WPF data binding validation errors and exceptions that occur during form data entry.
Much has been written about WPF data binding to business objects that implement the IDataErrorInfo interface. These past few weeks I have spent a good deal of time learning as much as possible about the WPF data binding pipeline; how and when it swallows or throws exceptions; how the source object exceptions and validation rules are reported through the data binding pipeline; finally the different ways available to the developer to report this information to the user. It sounds complicated but in reality it’s not.
The developers understanding of this topic is essential if they desire to write user friendly, stable and maintainable WPF data entry type applications. I hope that this WPF Sample application can help you to understand the various points of failure and how the WPF data binding pipeline responds and reports them. Please watch this short introductory video that explains the application, its purpose and how to get the most from it.
UI Demonstration Video

The video link require Microsoft Silverlight 1.0. If you do not have it, you will be prompted to install it when you click one of the links. After the short installation is completed, close the browser window that you did the install in and re-click the video you want to watch. You can also download Silverlight here. Windows XP or Vista required.
Handling and Reporting WPF Data Binding Validation Errors and Exceptions Video
Using The Demo Application
The purpose of this demo application is to allow you to generate different validation errors and run-time exceptions and view how this information is transferred to the UI controls from the WPF data binding pipeline. The exceptions are generated in different locations in the bound object so that you can understand the dynamics of an exception being thrown from each location since WPF does not handle each uncaught exception the same. Additionally, the application uses two different Validation.ErrorTemplates so that you can compare them and see why one is better than the other.
After viewing the video, run the application and play around with it. Then place some break points in the code and step through it at different points in the data binding cycle. Compare the UI experience with your own applications to see that you have covered all the bases. If I missed any please post a comment or fire me an email so I can correct this post and learn more about WPF in the process.
WPF Data Binding Pipeline
The MSDN documentation topic Data Binding Overview provides a very detailed explanation of each phase of the data binding cycle and how data validation functions. As I was writing this blog entry, I noticed that the new .NET 3.5 feature, data binding support for the IDataErrorInfo Interface has not yet been added to this page of the documentation.
As a side note, I did send a feedback message to Microsoft for their review. The “Send feedback on this topic to Microsoft” link is at the bottom of each page in the local copy of the MSDN documentation installed on your computer. There is also a send feedback link below the title of each page. If you notice documentation that needs updating, please send Microsoft a feedback message so that they can get it updated for all developers world wide. Trust me, Microsoft appreciates feedback from developers so they can deliver the best possible tools for the development community.
If you have a look at the Validation Process section, you’ll notice that when the IDataErrorInfo.Item property is checked is not mentioned. This is the part that I requested be updated. To determine when the IDataErrorInfo.Item property was read in the data binding cycle, I placed breakpoints within the code and step through it.
I added a DummyConverter to the first TextBoxes binding statement so that I could see when the Convert and ConvertBack methods were called also.
When a digit is entered into the first TextBox, the ConvertBack method is called. Then the Age property setter and then the IDataErrorInfo.Item property is read. When your reading the MSDN documentation, just understand that the IDataErrorInfo.Item property is read last.
Why is this important to understand? First any interruption in the data binding cycle leaves the additional checks downstream unverified. This could result in the UI being invalid due to some condition and the source object being valid. I cover this in great detail in my Code Project article, Business Object Declarative Programming; How To Implement Object Validation & Logging.
Where the developer places their property validation logic can have a big impact on determining object validation state. There are two places you can place code to trigger the verification of data in your source objects. First you can place the validation of a property in the IDataErrorInfo.Item property or call another method from this property’s getter to perform the validation or you can place the validation logic in the setter of the target property. If you choose the first location, your validation check for a specific property will only occur when the IDataErrorInfo.Item property is read. If you choose the second location, the property validation check will be performed every time the property is set. For this very simple example program I have placed the property validation check in the IDataErrorInfo.Item property getter.
I do not recommend performing data validation checks in the IDataErrorInfo.Item property getter in your applications. I recommend that you perform property validation checks when the property setter is called like I did in the Business Object Declarative Programming; How To Implement Object Validation & Logging article. I have also seen applications that perform these checks in methods that are called by the property setters, for example if you use the classes generated by the LINQ to SQL ORM designer, each property has a method that is called after the property is updated and you can validate the property there.
There are several reasons for my choice, the biggest is that when business objects are not data bound to a UI, but are being processed by other business objects inside your middle tier, the IDataErrorInfo.Item property will never be read, so your object state won’t be updated until you call a method to validate the entire object. Not saying that you couldn’t do this, maybe it’s my personal preference. Bottom line is, just understand how the various design choices you make effect your application.
If your following me consider if the data binding cycle gets interrupted, it’s important to understand how these various interruptions can effect the reported valdiation state of business object bound to the UI. You will see in the video and down below that the source object may not get updated when the data binding cycle gets updated. Knowing this can happen will help you to develop bullet proof applications that deal with real world data entry errors correctly.
Entering 0 – 150
When you enter values between 0 and 150, not icluding 99, 100 or 101, each TextBox will be updated as you enter each digit. I set the UpdateSourceTrigger property to PropertyChanged as opposed to the default value of LostFocus. I did this to make the demo more reactive. For business applications, you’ll probably want to wait until the user moves to the next field before updating the source object or running validation checks.
Entering a Non-Digit Character
When you enter a non-digit character, the data binding pipeline will catch the System.FormatException when it attempts to set the Age property which is an Integer to a non-numeric value.
If the TextBox binding statement has the ValidatesOnExceptions property set to True, the System.FormatException will be added to the TextBoxes Validation.Errors collection, if the ValidatesOnExceptions property is set to False which is the default, the exception will be swallowed up by the data binding pipeline and you and the user will not get any notification.
Entering 99 – Exceptions in the IDataErrorInfo.Item Property
When you enter 99 into the TextBoxes, the IDataErrorInfo.Item property getter will throw an exception that is caught within the getter and the exception message is then returned as the result of the property getter.
Take my advice, you do not want an exception to be thrown from the IDataErrorInfo.Item property getter. An exception thrown when this property is being read will be eaten in a release build by the WPF data binding pipeline and you and/or the user will never know something is wrong until other things start breaking. So I strongly recommend that you catch, log and handle any exceptions your getter code or any code the getter may call.
Entering 100 – Exception will be Thrown From The Customer.Age Property Setter
Entering 100 into the TextBoxes will cause the Customer.Age property to throw an exception. If the TextBoxes binding property, ValidatesOnDataErrors is True, then this exception will be reported to the UI. If ValidatesOnDataErrors is False which is the default, the exception will be swallowed up by the data binding pipeline and you and the user will not get any notification.
Read this carefully, I didn’t make a mistake. If the source object property setters throw an exception, it is the ValidatesOnDataErrors binding property that determines if that exception is reported and not the ValidatesOnExceptions. Remember that in .NET 3.0 exceptions where thrown to indicate a broken validation rule when the property setter was called and the TextBox binding was set up to report the message of those exceptions. Go ahead and change the XAML markup property values in Window1.xaml and observe how the UI reacts to the different property values in the TextBox binding statement.
Entering 101 – Exception will be Thrown From The Customer.Age Property Setter that Contains an InnerException
Entering 101 into the TextBoxes will cause the Customer.Age property to throw an exception that contains an InnerException. The same information about ValidatesOnDataErrors applies here also.
This condition is where the Validation.ErrorTemplate provided in this blog entry and the Code Project article I mentioned above, comes into play in the big way. The supplied template works with the ValidationErrorGetErrorMesageConverter to parse out the InnerException and return its message as opposed to returning the worthless message of the outter wrapper Exception.
Let’s Look At Some Code!
Customer Object
Imports System.ComponentModel Public Class Customer Implements IDataErrorInfo Private _intAge As Integer Public Property Age() As Integer Get Return _intAge End Get Set(ByVal Value As Integer) _intAge = Value If Value = 100 Then Throw New Exception( _ "Exception from the Age setter. This is not a rule violation, " _ & "this is just to show what an exception thrown by the setter " _ & "will look like in the UI.") ElseIf _intAge = 101 Then ThrowExceptionWithInnerExecption() End If End Set End Property Public ReadOnly Property [Error]() As String _ Implements System.ComponentModel.IDataErrorInfo.Error Get 'not using the property in this demo Return Nothing End Get End Property ''' <summary> ''' You do not want an exception to be thrown from this property. ''' ''' An exception thrown when this property is being read will be eaten in ''' a release build by the WPF data binding pipeline and you and/or the ''' user will never know something is wrong until other things start ''' breaking. ''' ''' So you MUST catch, log and handle any exceptions your code that could ''' possibly throw. ''' ''' I have placed this code in a Try Catch block to show how to ''' return a message to the UI. ''' </summary> Default Public ReadOnly Property Item(ByVal columnName As String) As String _ Implements System.ComponentModel.IDataErrorInfo.Item Get Dim strResult As String = Nothing Try If columnName = "Age" AndAlso _intAge = 99 Then ' let's blow up the applicatino for demo purposes Throw New Exception( _ "Exception throw in IDataErrorInfo.Item Age can't be 99.") ElseIf columnName = "Age" AndAlso (_intAge < 0 OrElse _intAge _ > 150) Then 'standard broken validation rule message strResult = _ "Age must not be less than 0 or greater than 150." End If Catch ex As Exception '1. log your exception #If DEBUG Then '2. set the message 'this is a good practice when debugging your applications If ex.InnerException IsNot Nothing Then strResult = ex.InnerException.Message Else strResult = ex.Message End If #Else '2. set the message strResult = _ "Bummer. Internal application glitch. Please contact " _ & "technical support." #End If End Try Return strResult End Get End Property Private Sub ThrowExceptionWithInnerExecption() Dim ex As New Exception( _ "This is the outer exception from ThrowExceptionWithInnerException.", _ New Exception( _ "This the in inner exception. Exception thrown by the " _ & "ThrowExceptionWithInnerException method, called by the Age setter. " _ & "This is not a rule violation, this is just to show what an exception " _ & "thrown by the setter will look like in the UI.")) Throw ex End Sub End Class
I have provided inline comments for this class. Just notice the #If DEBUG conditional block. This block allows the developers running a debug version of the code to view either the exception or inner exception message and the user that runs a release build to have a user friendly message displayed. The most important step in this code is #1, which is to log the exception so you can correct it.
Since we are referring to an inner exception, let’s look at one way to parse inner exceptions and get their messages as opposed to the outer exception message.
ValidationErrorGetErrorMessageConverter
''' <summary> ''' Converter that returns the ValidationError.ErrorContent or the first ''' inner exception message. ''' ''' This converter is handly because it will return the message from an ''' InnerException or the ErrorContent. ''' ''' Some data binding exceptions are package in a ''' System.Reflection.TargetInvocationException and this converter will ''' return the message from the actual exception rather than the useless ''' TargetInvocationException message. ''' ''' This converter usefulness is demonstrated when IDataErrorInfo property ''' validation routines throw exceptions. Those exceptions will bubble ''' through the WPF data binding pipeline and the InnerException will be ''' displayed using this converter. ''' </summary> <ValueConversion(GetType(ValidationError), GetType(String))> _ Public Class ValidationErrorGetErrorMessageConverter Implements IValueConverter #Region " Methods " Public Function Convert(ByVal value As Object, _ ByVal targetType As System.Type, _ ByVal parameter As Object, _ ByVal culture As System.Globalization.CultureInfo) As Object _ Implements System.Windows.Data.IValueConverter.Convert Dim sb As New System.Text.StringBuilder(1024) For Each objVB As ValidationError In DirectCast(value, _ System.Collections.ObjectModel.ReadOnlyObservableCollection(Of _ ValidationError)) If objVB.Exception Is Nothing OrElse objVB.Exception.InnerException Is _ Nothing Then sb.AppendLine(objVB.ErrorContent.ToString) Else sb.AppendLine(objVB.Exception.InnerException.Message) End If Next 'remove the last line feed If sb.Length > 2 Then sb.Length -= 2 End If Return sb.ToString End Function Public Function ConvertBack(ByVal value As Object, _ ByVal targetType As System.Type, _ ByVal parameter As Object, _ ByVal culture As System.Globalization.CultureInfo) As Object _ Implements System.Windows.Data.IValueConverter.ConvertBack Throw New NotSupportedException End Function #End Region End Class
The above Convert function not only returns the inner exception message if there is one, it also returns a String message from each ValidationError in the Validation.Errors collection for that TextBox. This is a nice feature to have since this object is a collection.
Notice that the value passed to this converter is the entire Validation.Errors collection and not just one element of the collection.
This converter is called in the Validation.ErrorTemplate for the TextBox.
Window1 XAML Markup
<Window x:Class="Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:src="clr-namespace:ValidationErrorTemplate" xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase" Title="WPF Data Binding Validation Errors and Exceptions " Topmost="True" Height="500" Width="600"> <Window.Resources> <src:Customer x:Key="data" /> <src:DummyConverter x:Key="dummyConverter" /> <ControlTemplate x:Key="validationTemplate"> <DockPanel> <DockPanel.Resources> <src:ValidationErrorGetErrorMessageConverter x:Key="validationErrorGetErrorMessageConverter" /> </DockPanel.Resources> <TextBlock Margin="5,0,5,0" Foreground="Red" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Top" Text="*" ToolTip="{Binding ElementName=errorAdorner, Path=AdornedElement.(Validation.Errors), Converter={StaticResource validationErrorGetErrorMessageConverter}}" /> <AdornedElementPlaceholder x:Name="errorAdorner" /> <TextBlock Width="400" Margin="5,0,0,0" TextWrapping="Wrap" Foreground="Red" FontSize="12" Text="{Binding ElementName=errorAdorner, Path=AdornedElement.(Validation.Errors), Converter={StaticResource validationErrorGetErrorMessageConverter}}" /> </DockPanel> </ControlTemplate> <Style x:Key="textBoxInError" TargetType="{x:Type TextBox}"> <Style.Triggers> <Trigger Property="Validation.HasError" Value="true"> <!-- Using this method to display errors has several drawbacks. 1. If the Target TextBox has a ToolTip assigned, this error message will not be displayed. 2. This only shows the first validation error, if there are more than one, you will not see it. 3. This method will not show you the correct information if an exception is wrapped in another exception. You must be able to get to the InnerException, using this method you can't. --> <Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}" /> </Trigger> </Style.Triggers> </Style> <Style TargetType="{x:Type Paragraph}"> <Setter Property="Margin" Value="5" /> </Style> </Window.Resources> <StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="Enter Age" Margin="10" /> <TextBox ToolTip="Please enter your age." Width="75" VerticalAlignment="Top" Margin="10" Text="{Binding Source={StaticResource data}, Path=Age, Converter={StaticResource dummyConverter}, diagresentationTraceSources.TraceLevel=High, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" Validation.ErrorTemplate="{StaticResource validationTemplate}"/> </StackPanel> <StackPanel Margin="0,50,0,0" Orientation="Horizontal"> <TextBlock Text="Enter Age" Margin="10" /> <TextBox Width="75" VerticalAlignment="Top" Margin="10" Text="{Binding Source={StaticResource data}, Path=Age, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" Style="{StaticResource textBoxInError}" /> </StackPanel> <StackPanel Margin="0,10,0,0" Orientation="Horizontal"> <TextBlock Text="Enter Age" Margin="10" /> <!-- If you set a ToolTip on a TextBox and then assign that ToolTip the error message in a style as many examples show you to do, the error message will not be displayed in the ToolTip. --> <TextBox ToolTip="This TextBox's error messages will not show up because this ToolTip is set on the TextBox." Width="75" VerticalAlignment="Top" Margin="10" Text="{Binding Source={StaticResource data}, Path=Age, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" Style="{StaticResource textBoxInError}" /> </StackPanel> </StackPanel> </Window>
If you look in the Windows.Resources, you’ll notice a ControlTemplate and Style that targets TextBoxes. These are both Validation.ErrorTemplates.
The ControlTemplate is applied to only the top TextBox. This is the template that displays the error message in a ToolTip for the TextBlock that displays the ” * ” and also displays the error message in a TextBlock to the right of the TextBox.
Have a close look at the ToolTip and Text property binding statements. Notice that the ValidationErrorGetErrorMessageConverter is passed the Validation.Errors object of Type, ReadOnlyObserveableCollection(Of ValidationError). This is an important distinction between this code and most example code I’ve seen. This template and converter combination make it possible to view any inner exception error messages caught by the data binding pipeline.
If you now compare the ControlTemplate with the Style below it, you’ll see a number of possible drawbacks that the Style has. This Style is how most examples I’ve seen are marked up.
Can I suggested that you evaluate your code and ensure that your needs are covered and that you’re not potentially missing exception messages or multiple ValidatonError objects in the Validation.Errors collection. Don’t forget about the issues with using a trigger to set the text in a ToolTip as this can cause your error message to not be displayed in the UI as expected.
System.Diagnostics.PresentationTraceSources.TraceLevel=High
When I was writing Part 3 of the WPF Business Application Series I was reading and studying the MSDN data binding documentation. I came across a little gem at the bottom of that MSDN documentation page.
Take a look at the first TextBox again and you’ll see this in the binding statement. Now, go run the program an watch the Visual Studio Output window. Change the first TextBox and observer all the messages you are getting. While this tool does not return every single event or action performed by the data binding pipeline, it does provide good insight into what is going on. You can learn a good bit from reading the output of this. I suggest that you read the MSDN topic for this setting as you can use this setting with other objects beside a Binding object.
To really learn about debugging WPF data bindings, read Bea Costa’s http://www.beacosta.com/blog/?p=52 blog entry. Bea is the First Lady of data binding, a true master of WPF and data binding.
Microsoft MVP and .NET Fanatic Corrado Cavalli has just posted two super articles on debugging with PresentationTraceSources.TraceLevel. The first is written in his first language, Italian and the second in English.
Italian version of data binding debugging using PresentationTraceSources.TraceLevel
English version of data binding debugging using PresentationTraceSources.TraceLevel
Close
Source Code: After downloading the source code you MUST change the file extension from .zip.DOC to .zip. This is a requirement of WordPress.com.
Hope you can learn just a little bit more about WPF from this article and the Sample Series.
Just a grain of sand on the worlds beaches.




April 3, 2008 at 2:38 am |
[...] He has posted an informative article entitled Handling and Reporting WPF Data Binding Validation Errors and Exceptions. [...]
April 3, 2008 at 7:20 am |
you’re the best…..
April 3, 2008 at 7:22 am |
Marlon,
Just following your lead!
Cheers and thank you,
Karl
April 10, 2008 at 8:55 am |
Karl Hello
There is something I can’t really understand with WPF. Where are the DataSets in WPF? I mean I haven’t seen and example tutorial reagarding DataBinding where DataSets are used.
So in the pass few days I have been trying to adopt what you and other WPF “masters” have accomplished , but instead of a custom object I’m using a typed DataSet.
When using DataSets there is a dillema when combining it with a controls, that shows items like a ListBox.
Let us a say that we have a typed dataset ds and a table tName.
If you choose to give ItemsSource the ds.tName then DataItemTemplate must be of type System.Data.DataRowView which produces a serious question. How will IDataErrorInfo will be implemented? The only logical place i have access is the typed row class but the control will have DataRowView type items, so there will be no Validation
Another question which is not related to your article, and for give for posting it here is that while reading the last year about WPF i have come to understood that if in resources are declared DataItemTemplates for various types then they are automatically used. But when a dataview is practically given all objects are of DataRowView type so a distinction cannot be made.
Another solution is that you can give ItemsSource the actual Row Collection and everything will work fine, but when a row is added to the table, the control will not be notified which is really inconvinient.
Am I’m missing something? It strikes me odd, that MS has neglected so much about typed datasets in WPF. I percieve datasets to be the most efficient storage mechanism for database related data.
April 10, 2008 at 9:20 am |
Alex,
I have not done anything with typed dataset and wpf. I used them in my asp.net applications but not here.
Josh has a blog post on using datasets to bind to a treeview:
http://joshsmithonwpf.wordpress.com/2007/05/05/binding-a-treeview-to-a-dataset/
When I get back from the MVP Summit in I’ll fire up a test application and see if I can give you good answers. I don’t want to fire off somthing without testing it first.
Keep in mind, WPF databinding takes advantage of property and object change notification. As long as these objects provide the required information, everything works fine.
Is there a specific reason you’ll using Typed Datasets over class objects or LINQ query results?
Have a great day Alex!
Karl
April 10, 2008 at 2:36 pm |
I have not decided yet over DataSets or something else.
Generally I prefer DataSets because they are realy fast, and resemble very much an actual Database.
Addiniotally they are great to hold data in states like added or deleted or modified. The latest is greatly used with OpenXML within a stored procedure.
As I understand it WPF checks for specific Interfaces on each object and acts accordingly. And this is where the problem lies. Databinding with DataSets indruduces an intermediate layer of objects known as DataView and DataRowView which are constructed internally.
Have a nice time Karl
If I find anything I will let you know.
April 14, 2008 at 7:51 am |
Karl Hello again
I have found some stuff regarding my above comment and the DataSets.
I will be soon posting on my blog, but these last few days my hand hurts a lot so I’m keeping mouse and keyboard interaction at minimal.
I’m letting you know so you don’t loose time, if I may use the phrase.