WPF Validation - Using INotifyDataErrorInfo | .NET Land (kmatyaszek.github.io)

In the .NET 4.5 was introduced new interface INotifyDataErrorInfo which enables data entity classes to implement custom validation rules and expose validation results asynchronously. This interface has three members:

HasErrors property indicates whether there are any validation errors

GetErrors method returns an IEnumerable that contains validation errors for the specified property (when the propertyName parameter isn’t equal to null or empty string) or for the entire entity (when the propertyName parameter is equal to null or empty string)

ErrorsChanged event must occur when the validation errors have changed for a property or for the entity

As GetErrors returns IEnumerable you can return multiple errors per property. Also, you can return custom error object (this is not possible using IDataErrorInfo interface). As you can see this new interface provides more flexible validation model in WPF. By default, ValidatesOnNotifyDataErrors is set to true so you don’t have to set this explicit in the binding expression. Below you can see the result of my example program (as you can see TextBox has two errors).

Below you can see an example implementation of the INotifyDataErrorInfo:

public class MainViewModel : BindableBase, INotifyDataErrorInfo

{

private string _userName;

private readonly Dictionary> _errorsByPropertyName = new Dictionary>();

public MainViewModel()

{

UserName = null;

}

public string UserName

{

get => _userName;

set

{

_userName = value;

ValidateUserName();

RaisePropertyChanged();

}

}

public bool HasErrors => _errorsByPropertyName.Any();

public event EventHandler ErrorsChanged;

public IEnumerable GetErrors(string propertyName)

{

return _errorsByPropertyName.ContainsKey(propertyName) ?

_errorsByPropertyName[propertyName] : null;

}

private void OnErrorsChanged(string propertyName)

{

ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));

}

private void ValidateUserName()

{

ClearErrors(nameof(UserName));

if (string.IsNullOrWhiteSpace(UserName))

AddError(nameof(UserName), "Username cannot be empty.");

if (string.Equals(UserName, "Admin", StringComparison.OrdinalIgnoreCase))

AddError(nameof(UserName), "Admin is not valid username.");

if (UserName == null || UserName?.Length <= 5)

AddError(nameof(UserName), "Username must be at least 6 characters long.");

}

private void AddError(string propertyName, string error)

{

if (!_errorsByPropertyName.ContainsKey(propertyName))

_errorsByPropertyName[propertyName] = new List();

if (!_errorsByPropertyName[propertyName].Contains(error))

{

_errorsByPropertyName[propertyName].Add(error);

OnErrorsChanged(propertyName);

}

}

private void ClearErrors(string propertyName)

{

if (_errorsByPropertyName.ContainsKey(propertyName))

{

_errorsByPropertyName.Remove(propertyName);

OnErrorsChanged(propertyName);

}

}

}

And below snippet of code shows you how you can show to user multiple errors to single property:

A complete example is available on the following link: https://github.com/kmatyaszek/WPFValidationINotifyDataErrorInfo

 

WPF validation using INotifyDataErrorInfo - Dot Net For All

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

WPF validation using Validation Exception and Validation rules.

WPF validation using IDataErrorInfo

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.

 

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.

 

参考链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。