The DataErrorNotifier
class in the downloadable sample code is a reusable implementation of the INotifyDataErrorInfo
interface.
DataErrorNotifier
makes implementing asynchronous validation easy. With the addition of a single validation method to your viewmodel, DataErrorNotifier
manages the list of errors and takes care of raising data error events. Furthermore, validation can be restricted by registering only those properties that you want to be validated.
DataErrorNotifier
is designed to validate classes that implement a custom IValidateData
interface, such as the ViewModelBase
class. The validation logic has been decoupled from the ViewModelBase
class to be reusable for other types as well.
The DataErrorNotifier
requires an instance of IValidateData
. The IValidateData
interface defines an asynchronous validation mechanism with a nonblocking BeginValidate
method and an event to signal when validation is complete (see Figure 26.11).
The ViewModelBase
class implements IValidateData
. ViewModelBase
creates an instance of the DataErrorNotifier
class and passes itself to the DataErrorNotifier
’s constructor, as shown:
protected ViewModelBase()
{
dataErrorNotifier = new DataErrorNotifier(this, this);
...
}
DataErrorNotifier
subscribes to the viewmodel’s PropertyChanged
event. When the PropertyChanged
event is raised, validation is performed automatically.
If you want validation to be performed prior to the setting of the property’s backing field, modify the DataErrorNotifier
so that it subscribes to the PropertyChanging
event of the viewmodel rather than its PropertyChanged
event.
The DataErrorNotifier
takes responsibility for the INotifyDataErrorInfo
implementation. Ordinarily, a viewmodel calls only the ViewModelBase
’s AddValidationProperty
and IsComplete
methods. Both the ViewModelBase
class and the DataErrorNotifier
implement INotifyDataErrorInfo
. The ViewModelBase
class, however, merely calls through to its DataErrorNotifier
instance.
To register a property for validation in a viewmodel, the AddValidationProperty
is called in the constructor of the viewmodel, as demonstrated in the following excerpt:
AddValidationProperty(() => ARequiredStringProperty);
AddValidationProperty
causes the DataErrorNotifier
to automatically attempt to validate the property when the property changes, or when the viewmodel is being validated in its entirety.
The lambda expression provides the ViewModelBase
class with the means to resolve both the property and the name of the property. The ViewModelBase.AddValidationProperty
method retrieves the name of the property and passes it and a Func
to the DataErrorNotifier
, as shown:
protected void AddValidationProperty(Expression<Func<object>> expression)
{
PropertyInfo propertyInfo = PropertyUtility.GetPropertyInfo(expression);
string name = propertyInfo.Name;
Func<object> getter = (Func<object>)Delegate.CreateDelegate(
typeof(Func<object>),
this,
propertyInfo.GetGetMethod());
dataErrorNotifier.AddValidationProperty(name, getter);
}
DataErrorNotifier
stores the association between the property name and the Func
, which allows the property to be retrieved by name during validation.
The AddValidationProperty
method of the DataErrorNotifier
is shown in the following excerpt:
public void AddValidationProperty(string name, Func<object> property)
{
lock (propertyDictionaryLock)
{
propertyDictionary[name] = property;
}
}
3.12.107.31