Confessions of a .NET Developer!

WPF Tutorial – How to use IDataErrorInfo in WPF

In this post I shall explain how to use IDataErrorInfo in a WPF Application. IDataErrorInfo takes into consideration the powerful databinding that WPF has provided. If you are Binding your controls using the Binding techinque, then for validations, IDataErrorInfo is recommended as it is easier to implement.

Lets get started!

First we will create a User class :

    class User:IDataErrorInfo,INotifyPropertyChanged
    {

        private String _firstName;
        public String FirstName
        {
            get { return _firstName; }
            set
            {
                _firstName = value;
                OnPropertyChanged("FirstName");
            }
        }

        private String _lastName;
        public String LastName
        {
            get { return _lastName; }
            set
            {
                _lastName = value;
                OnPropertyChanged("LastName");
            }
        }

        private int _age;
        public int Age
        {
            get { return _age; }
            set
            {
                _age = value;
                OnPropertyChanged("Age");
            }
        }

        #region IDataErrorInfo Members

        public string Error
        {
            get { return String.Empty; }
        }

        public string this[string columnName]
        {
            get
            {
                String errorMessage = String.Empty;
                switch (columnName)
                {
                    case "FirstName":
                        if (String.IsNullOrEmpty(FirstName))
                        {
                            errorMessage = "First Name is required";
                        }
                        break;
                    case "LastName":
                        if (String.IsNullOrEmpty(LastName))
                        {
                            errorMessage = "Last Name is required";
                        }
                        break;
                    case "Age":
                        if (Age < 1)
                        {
                            errorMessage = "Age cannot be less than one";
                        }
                        break;
                }
                return errorMessage;
            }
        }

        #endregion
    
        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler  PropertyChanged;
        private void OnPropertyChanged(String propertyName)
        {
            if(PropertyChanged!=null)
            {
                PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion
}

In the above class, I implemented two Interfaces, IDataErrorInfo to provide validation and INotifyPropertChanged to notify that the Property has changed.
You can see the IDataErrorInfo readonly properties.
The second one is what we need. It has a column name parameter, which will be the Properties of the User class.
For each property, we are assigning specific rules such as, the FirstName and the LastName should not be empty. The age should not be less than one. The errorMessage field will be initialised with the Error Message that you want to show when these rules are not followed.

Then there is a Users class which will inherit the ObservableCollection(of User). It will hold the collection of User.

   class Users:ObservableCollection
    {
        public Users()
        {
            Add(new User()
            {
                FirstName = "Tarun",
                LastName = "Singh",
                Age = 22
            });
        }
    }

So now we can create a window to display our data.

Window

Window

And here is the XAML :
I shall XAML parts by parts:

Here is the Resources used :

Resources - TextBox

Resources - TextBox

Here I have created a style for all the textboxes. Note the TargetType, I have written it as {x:Type TextBox}, thus this style will be applied to all the Style in the Grid. Firstly, I have added a Trigger to set the ToolTip whenever there is a Validation Error.
Next I have provided the ErrorTemplate for the textbox. Basically whenever there is a validation we can provide our own template for it using AdornedElementPlaceHolder(pretty long one!). This will place a layer above the element, as in this I placed a Border above the TextBox with a Red BorderBrush. And then I have provided a TextBlock to the Right of the TextBox which will give a Red star indicating an error together with the ToolTip.

Next step will be disabling the Button when Validation fails in any of the TextBoxes.

Resources - Button

So here in the XAML, you can see I have added DataTrigger(ya i should have used a MultiDataTrigger with Conditions, but all the Conditions will have to be true so i will be coming with a solution for this!). Each datatrigger is bound to textboxes to check for Validation Errors, if errors found then, the button will be disabled! Cool isn’t it!

Now lets turn our attention to the XAML of Controls that we have used as this part does the Binding.
SO here it is :

XAML - Controls

XAML - Controls

There are two important things to take care of.
First is the use of ValidatesOnErrors. This should be declared in Binding Expression and set to True if we are using IDataErrorInfo.

Second is the use of Binding.ValidationRule. There are two reasons why we are using this is. First is because if we leave Age empty, no validation will be evaluated. Second is if on adding characters to the age, still no validation will be fired. Try removing the Binding.ValidationRule and you can see the difference. So to handle this, we will create a class AgeValidation to solve this problem.

Here is the class:

    class AgeValidation:ValidationRule
    {
        public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
        {
            int age;
            Boolean noIllegalChars;
            noIllegalChars = int.TryParse(value.ToString(), out age);

            if (value.ToString().Length < 1)
            {
                return new ValidationResult(false,"Age field cannot be empty");
            }
            else if(noIllegalChars==false)
            {
                return new ValidationResult(false, "Illegal Characters");
            }
            else
            {
                return new ValidationResult(true, null);
            }
        }
    }

This class inherits the ValidationRule and overrides the ValidationRule function. Here we can check for illegal characters and also check for empty entry in the Textfield. This function will return the Error Message that you want to show. Awesome! 🙂

Do add the namespace to locate this class in the assembly.

xmlns:local=”clr-namespace:WpfApplication1″;

Finally in the code-behind of our window, in the class constructor, we can provide the DataContext like below:

    public partial class Window2 : Window
    {
        public Window2()
        {
            InitializeComponent();
            DataContext = new Users();
        }
    }

Lets see its working now!

Running Example

Cool!

That’s it!
So this is how Validation is handled in WPF.
Hope you enjoyed it! Do leave your comments, suggestions, feedbacks on how you liked this article. 🙂
Have a nice day!

Advertisements

March 3, 2011 - Posted by | WPF

10 Comments »

  1. Thank you for the helpful post. It was very useful to see how to disable a particular button based on invalid text in a TextBox.

    Comment by Peter | November 17, 2011 | Reply

  2. Thank you so much! I have been searching all afternoon how to disable a button, found many solutions but none of them worked until yours.

    Comment by nevrothwen | December 26, 2011 | Reply

  3. Shouldn’t you be avoiding the use of control names in the Button’s IsEnabled validation? Wouldn’t that validation be better off as a DependencyProperty or something that could be part of your DataContext?

    Comment by G | May 15, 2012 | Reply

  4. Very nice tutorial. Thanks a lot..

    Comment by Lavanya | August 11, 2012 | Reply

  5. i can;t use a control name because my controls are in DataTemplate. when i am trying to use them i am getting binding error :–

    Cannot find source for binding with reference ‘ElementName=ComboBoxOutALanguage’. BindingExpression:Path=(0); DataItem=null; target element is ‘Button’ (Name=”); target property is ‘NoTarget’ (type ‘Object’)

    is there any other way i can use this solution with data template.?

    Comment by kamal | November 2, 2012 | Reply

  6. Thanks ever so much. This is awesome!

    Comment by Paul Whiteman | August 11, 2013 | Reply

  7. You completely lost me at the XAML thing.

    Comment by Ben Beckers | March 17, 2014 | Reply

  8. Hi, I don’t understand your reasons to use Binding.ValidationRule here because the validation works also without an extra validation rule. Your explanations “f we leave Age empty, no validation will be evaluated. Second is if on adding characters to the age, still no validation will be fired” are not true. I found these explanations little peculiar so I typed your whole project excluding the ValidationRule and it works perfect, i.e., if I delete the “22” in Age then the red border appears and the button is disabled and also if I type characters to age the red border also appears and the button also disables. So I did not understand your point in using this extra validation rule 🙂

    Comment by Ilker | April 13, 2014 | Reply

  9. it show me that it can not find the property MinimumAge in the type AgeValidation

    Comment by Ignacio L | November 18, 2014 | Reply

  10. if(PropertyChanged!=null)
    {
    PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
    }

    needs to be:

    var action = PropertyChanged;
    if (action != null)
    {
    action(this, new PropertyChangedEventArgs(propertyName));
    }

    Comment by Daniel | February 1, 2016 | Reply


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: