WPF: Validation made easy with IDataErrorInfo


Recently I came across an interface called IDataErrorInfo used for validation, and apparently it’s been around since the early days. I’ve never seen any use of it, or heard of it’s usage until now. It’s been used with WPF validation and integrates very seamlessly too.

  1. Step 1: Create data model with IDataErrorInfo
  2. Step 2: Databind the data to your input fields
  3. Step 3: Customize the Error Template to get different look and feel

WPFValidation

As you can see from the screenshot, validation is triggered when the fields input fail the criteria. The “Add” button on the screen is also disabled/enabled in accordance to the validation via the use of WPF Command System.

Step 1: Creating data model with IDataErrorInfo

To get started with this, you first need a model that implements IDataErrorInfo, like so…

public class Customer : IDataErrorInfo
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }

    #region IDataErrorInfo Members

    public string Error
    {
        get { throw new NotImplementedException(); }
    }

    public string this[string columnName]
    {
        get
        {
            string result = null;
            if (columnName == "FirstName")
            {
                if (string.IsNullOrEmpty(FirstName))
                    result = "Please enter a First Name";
            }
            if (columnName == "LastName")
            {
                if (string.IsNullOrEmpty(LastName))
                    result = "Please enter a Last Name";
            }
           if (columnName == "Age")
            {
                if (Age < = 0 || Age >= 99)
                    result = "Please enter a valid age";
            }
            return result;
        }
    }

    #endregion
}

Looking at the interface implementation, we put in checks for the Property Names we are interested in validating, and return an error message for each one that failed the criteria. For example, we are validating that the first and last names are not empty fields.

Step 2: Databind the data to your input fields

So how does WPF know how to use this interface to validate the input fields? We make use of the coolness of data binding! Below is a snippet of a TextBox with data binding.

<textbox x:Name="tbFirstName" Grid.Row="0" Grid.Column="1" Validation.Error="Validation_Error"
         Text="{Binding UpdateSourceTrigger=LostFocus, Path=FirstName,
                ValidatesOnDataErrors=true, NotifyOnValidationError=true}" />

UpdateSourceTrigger specifies the condition for updating the source. I have set it to LostFocus instead of PropertyChanged, because PropertyChanged will degrade performance by triggering an update on every keystroke. There also another option called Explicit, meaning you have to trigger the update manually by calling the UpdateSource method.

ValidatesOnDataError is the super star behind all this. By flipping this flag on, the databinding will be able to communicate with any data types that implement IDataErrorInfo. (You might also want to read more about Validation.Error event and NotifyOnValidationError.)

Now that we understand how all these tie together, next question is how to display the error messages. By default, WPF notifies user of a error by highlighting the input field with a red border only. To display the error message or create a whole new look (like how I’ve done it), you need to do some work.

There’s a Validation static class in the WPF framework that’s designed for supporting data validation. You can attach it’s properties and event to any UIElement, such as the Validation.Errors property which holds a collection of error messages. We can now make use of this property to display our error message, for example in a ToolTip when user mouse overs the error icon.

Step 3: Customize the Error Template to get different look and feel

In WPF you can customize almost anything on the UI which is awesome. In order to customize our look and feel of the error, we change the ErrorTemplate of our textbox by defining a new style.

<style TargetType="{x:Type TextBox}">
    <setter Property="VerticalAlignment" Value="Center" />
    <setter Property="Margin" Value="0,2,40,2" />
    <setter Property="Validation.ErrorTemplate">
        </setter><setter .Value>
            <controltemplate>
                <dockpanel LastChildFill="true">
                    <border Background="Red" DockPanel.Dock="right" Margin="5,0,0,0" Width="20" Height="20" CornerRadius="10"
                            ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
                        <textblock Text="!" VerticalAlignment="center" HorizontalAlignment="center" FontWeight="Bold" Foreground="white">
                        </textblock>
                    </border>
                    <adornedelementplaceholder Name="customAdorner" VerticalAlignment="Center" >
                        <border BorderBrush="red" BorderThickness="1" />
                    </adornedelementplaceholder>
                </dockpanel>
            </controltemplate>
        </setter>
</style>

I’ve drawn the error icon very simply by wrapping a Border (with corner radius set properly) around a TextBlock. What’s of interest here is the AdornedElementPlaceholder, which like the name implies is a placeholder for an Adorner. So what is an Adorner? From my limited understanding, it’s basically a FrameworkElement that sits on top of your UI control on a different layer that is responsible for displaying visual cues. To me, it resembles a lot like the Decorator pattern, where you can enhance the look of your bound control without affecting it’s default state and behavior.

An example of customizing the Adorner is in the snippet above, where I put a red Border in it. When a validation error occurs, the Border appears around the control it is bound to, in this case the TextBox.

Lastly this line of Xaml code binds the ToolTip content to the first error message in the Validation.Errors collection.

ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"

WPF has loads of features, and I’m enjoying the process of discovery. It’s been great fun playing with it, and there will be more to come. Happy Coding.

Updated Source
Download the sample code here.

Share this post:
Posted in WPF. 31 Comments »

31 Responses to “WPF: Validation made easy with IDataErrorInfo”

  1. WPF: Validation Summary Control « Code Blitz Says:

    […] WPF: Validation made easy with IDataErrorInfo […]

  2. Veena Says:

    Nice article!!

  3. Scott Says:

    Very nice article!
    I have a couple of questions though

    Why do your text boxes not show the error when the program is loaded?

    I cannot seem to hide the error template after it has been shown, is it possible to hide the error template?
    (setting visibility to “Hidden” on the dock panel, textbox, or placeholder does not seem to do it)

    Thanks for helping me, I am new to WPF. Your validation example has saved me a ton of time.

    • Ed Foh Says:

      Hi Scott

      thanks for the question. I’m also still learning WPF, there’s just too much! 🙂

      I had a look at my code again, found a bug and fixed it too..lol. Anyways the reason why it’s not showing the error when program starts is due to the cause of binding the grid’s DataContext to a instance of a Customer as a resource key. I modified code to bind the grid to an initialized instance of a Customer in the code behind, and error triggered on startup. I’m not a 100% sure why that is, but that was my first suspicion.

      for your 2nd question, because the error is triggered on and off via databinding and the IDataErrorInfo interface, to turn it off requires a valid value in the textbox. It’s triggered on LostFocus, so click somewhere else on the screen and validation will occur.

      Hope that helps. You can download the updated sample code. I have modified it to trigger error on startup.

      • Scott Says:

        Thank you for such a detailed answer and you are super fast too. I was thinking/hoping I would get the reply sometime next week as this post has been around awhile.

        I am looking forward more to net 4.0 as there will be better support for validation. (well that and more)

        You have helped me a ton. Thanks.

        Have Fun,
        -Scott

  4. Hugo Says:

    Hi. Great article. I’m having a bit of a problem showing the styles after validation, but I’m working on that. I have a question though: How would you implement such validation on a PasswordBox control, given it doesn’t support binding?

    • Ed Foh Says:

      Hi Hugo

      thanks. First of all, this approach only works with databinding. I guess I’m wondering why you would want to databind to a PasswordBox Control. I’m thinking the WPF Team left this out because the password string would have to be stored in memory for databinding to work, thus becoming a security concern.

      I guess without databinding, you can still validate it yourself. If you still want to make use of IDataErrorInfo, there are other approaches, such as creating a custom control that inherits from PasswordBox and creating a dependency property for databinding. Or using Attached Properties which is a quicker approach.

      Here’s a good article that uses Attached Properties.

      http://blog.functionalfun.net/2008/06/wpf-passwordbox-and-data-binding.html

      hope this helps.
      Ed

      • Sirius Says:

        <>

        For example to let a user know they’ve not entered a password or that the password and comparison password you’ve asked them to enter match.

        Microsoft’s approach may work for them. However there are many scenarios when its doesn’t. If someone has gone to the lengths of hacking your code to grab a password, that it’s not dependency property and cannot be bound is not going to stop them.

        The functionalfun approach doesn’t play nice with MVVM frameworks like Caliburn.

  5. Dasha Says:

    This is awesome! Helped me a great deal but I can’t seem to figure out how to validate other controls such as ComboBox and Date-pickers. Any suggestions?

    • JR Says:

      Yeah I can’t seem to figure this out for the ComboBox control as well. I want to validate if nothing is selected, however, this doesn’t raise the “Validation.Error” event.

  6. WPF: Validation made easy with IDataErrorInfo « haipk Says:

    […] Step 1: Create data model with IDataErrorInfo […]

  7. Paras Sharma Says:

    Is there any way by which initially the red lines are not shown and when the user clicks on Add button validation takes place and if any error is there we can show the Red line?

  8. Nadege Says:

    Great thanks for this post. It’s very clear.

  9. Edgar Says:

    This is great!!!
    I have only one question, How can I validate the controls only when is enabled?

  10. youssef Says:

    Hi,
    I have used your validation in my program, but d’ont work.
    I use the same style for TextBox

    the difference to your exaple.
    i have a usercontrol and no window

    and the TextBox

    and in code behind:
    string IDataErrorInfo.Error
    {
    get
    {
    throw new NotImplementedException();
    //return null;
    }
    }

    string IDataErrorInfo.this[string propertyName]
    {
    get { return this.GetValidationError(propertyName); }
    }

    string GetValidationError(string propertyName)
    {
    if (Array.IndexOf(ValidatedProperties, propertyName) < 0)
    return null;

    string error = null;

    switch (propertyName)
    {
    case "ArtikelNr":
    error = this.ValidateArtikelNr();
    break;
    case "Pruefanweisung":
    error = this.ValidatePruefanweisung();
    break;
    case "SabMin":
    error = this.ValidateSabMin();
    break;
    case "SabMax":
    error = this.ValidateSabMax();
    break;
    case "HysMin":
    error = this.ValidateHysMin();
    break;
    case "HysMax":
    error = this.ValidateHysMax();
    break;

    case "TlBezeichnung":
    break;

    default:
    Debug.Fail("Unexpected property being validated on Lasertrimming data: " + propertyName);
    break;
    }

    return error;
    }

    #region ArtikelNr validation
    string ValidateArtikelNr()
    {
    if (IsStringMissing(this.ArtikelNr))
    {
    return "missing article number"; //TODO: Text der fehlermeldung in Ressource
    }
    else if (!IsValidArtikelNr(this.ArtikelNr))
    {
    //return "invalid Artikel number. at least 2 characters and only numbers and – are allowed"; //TODO: Text der fehlermeldung in Ressource
    return "invalid Article number"; //TODO: Text der fehlermeldung in Ressource
    }
    return null;
    }

    static bool IsStringMissing(string value)
    {
    return
    String.IsNullOrEmpty(value) ||
    value.Trim() == String.Empty;
    }

    static bool IsValidArtikelNr(string artikelNr)
    {
    if (IsStringMissing(artikelNr))
    return false;

    string artikelNrPattern = @"^[0-9]+-?[0-9]+$"; // kann nur Zahlen und bindestrich(-) enthalten. mindestens zwei Zeichen
    return Regex.IsMatch(artikelNr, artikelNrPattern, RegexOptions.IgnoreCase);
    }
    #endregion

  11. ram Says:

    error at line “” when i try to use the code copied from this site.

  12. WPF MVVM Validation using Fluent.Validation | 2bit-coder Says:

    […] found some great posts on using IDataErrorInfo with WPF, but this wasn’t as straight forward when using an MVVM model.  Then I found a great post on […]

  13. Itsho Says:

    Here’s your Style (formatted), for anyone having trouble copy&paste it 🙂

  14. Itsho Says:

    Here’s your Style (formatted), for anyone having trouble copy&paste it 🙂

    http://pastebin.com/j8KAGtwA

  15. Michael Kosak Says:

    Is IDataErrorInfo also intended to do the actual test? I have seen a half dozen ways to do data validation in WPF MVVM programs so far- this one works very nicely. But was it intended to do the validation testing – if so, then what about the ValidationRule class? or setting Validation ATTRIBUTE on a data item? It is an abundance of riches, but too much… I have worked on one program that did it several different ways. I liked this IDataErrorInfo method best of all because it consolidated everything, so my question is more “which way is best?” (I’ll pause while you all pick a side)

  16. Umar Says:

    Great code for someone like me learning all this WPF stuff but when I navigate away (to another tab) then return, the error indicators have all disappeared and won’t reappear until I manually change the text again.
    I can set something like, in the style:

    but I don’t know how to recreate the indicators. Can anyone help? Thanks

  17. Umar Says:

    Sorry, code got chopped, I hardly comment on things so no idea how to get it to show!

    Trigger Property=”Validation.HasError” Value=”True”
    Setter Property=”BorderBrush” Value=”Chartreuse”
    /Trigger

  18. dbnex B Says:

    While the article is nice, I am unable to get the tool-top and red circle showing? I only get the red line around the TextBox but that is default behavior of WPF.

  19. dbnex B Says:

    I can’t get the tool tip and red circle to show? The only difference I see is that in my case the Grid is inside a Border but other than that, everything is same?

  20. Ashwin singh Says:

    But i don’t want red textbox when form loads.. what is want is when my form loads i want to see my textbox with default black border and when i lost focus at that time i want to see red textbox with error.. please suggest
    Thanks in advance


Leave a comment