top of page

WPF validation using INotifyDataErrorInfo

In this article I will discuss about INotifyDataErrorInfo which is used to validate the data asynchronously in WPF. In my previous articles I have discussed about the ways to validate data entered in the UI.


Please find the previous articles link below


Validation using INotifyDataErrorInfo

  • Added in .NET 4.5 for WPF

  • It works on the same principle as IDataErrorInfo but it is based on the event driven mechanism which notifies for the validation errors asynchronously based on the input from some time consuming operation like service call. It will wait for the results to come back and eventually it will raise the event.

  • Set ValidatesOnNotifyDataErrors=True on binding.

  • Binding will call the GetErrors method of the INotifyDataErrorInfo when the property is set in the ViewModel through view.

  • Binding also subscribes to the ErrorsChanged event in the interface.

  • If the ErrorsChanged event is raised, it will go and re query the GetErrors method for the property for which the event is raised.

  • To implement this we need to manage a dictionary of errors per property as part of error.

  • One of the advantage of this over IDataErrorInfo is that we can return multiple errors per property.

Lets have a look at the INotifyDataErrorInfo interface in the below figure

INotifyDataErrorInfo interface


The interface has three members which the derived class need to implement. Whenever we are setting this validation, the HasErrors property is called by the binding which in turn calls the GetErrors method to return the error if the HasErrors return true. After some point when GetErrors is called the ErrorsChanged event is raised and it again calls GetErrors method. It is assuming that there are some asynchronous operation that filled the collection on which the GetErrors is working on.


As we can see the GetErrors method return the IEnumerable object. It means that it is working on some collection of the objects to get the errors.


Lets implement INotifyDataErrorInfo to our view model class. Please check the code below for the PersonVM class.

 public class PersonVM: INotifyPropertyChanged, INotifyDataErrorInfo
    {
        private string mobileNumber;

        public string MobileNumber
        {
            get { return mobileNumber; }
            set {               
                mobileNumber = value;
                PropertyChanged(this, new PropertyChangedEventArgs("MobileNumber"));
                GetErrorsForPhone(MobileNumber).ContinueWith((task) =>
                {
                    lock (_PropertyErrors)
                    {
                        _PropertyErrors["MobileNumber"] = task.Result;
                        ErrorsChanged(this, new DataErrorsChangedEventArgs("MobileNumber"));
                    }
                });
            }
        }

        private string name;

        public string Name {
            get { return name; }
            set
            {
                name = value;
                PropertyChanged(this, new PropertyChangedEventArgs("Name"));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged = delegate { };


        public bool HasErrors
        {
            get
            {
                return PropertyErrorsPresent();
            }
        }

        private bool PropertyErrorsPresent()
        {
            bool errors = false;
            foreach (var key in _PropertyErrors.Keys)
            {
                if(_PropertyErrors[key] != null)
                {
                    errors = true;
                    break;
                }
            }

            return errors;
        }

        public IEnumerable GetErrors(string propertyName)
        {
            lock (_PropertyErrors)
            {
                if (_PropertyErrors.ContainsKey(propertyName))
                    return _PropertyErrors[propertyName];
            }

            return null;
        }
      
        public event EventHandler ErrorsChanged = delegate { };
      

        Dictionary> _PropertyErrors = new Dictionary>();

        Task> GetErrorsForPhone(string value)
        {
            return Task.Factory.StartNew>(() =>
            {
                Thread.Sleep(5000);
                Regex regex = new Regex(@"^\D?(\d{3})\D?\D?(\d{3})\D?(\d{4})$");
                if (regex.Match(value) == Match.Empty)
                    return new List { "Invalid phone format" };
                else return null;

            });
        }
    }

In the above code I am checking for the validation of the MobileNumber property. To support the error collection for the property I have created a dictionary which will contain all the errors related to a property.


Let’s understand the code one step at a time.

  1. In the application if we are checking the MobileNumber to have a valid 10 digit number. And if we change to invalid number we will call the GetErrorsForPhone() method which is acting as a time consuming operation analogous to some service, which is being is used to validate the data.

  2. In the setter of the MobilePhone property we are continuing with the result of the GetErrorForPhone() method, which is a list of the string. And we set these errors for the “MobileNumber” property in the dictionary and raise the ErrorChanged event.

  3. When the ErrorChanged event is raised, it notifies the “MobileNumber” property’s binding and which calls the HasErrors property. If there are errors GetErrors() method is called by the binding.

  4. If we have entered some invalid format which is not as per our requirement we will get the validation error on the UI.


Conclusion:

In this article I have discussed the way in which we can use INotifyDataErrorInfo with example.


Source: Paper.li

0 comments

Comments


bottom of page