This is the second article in a planned series of articles concerning AOP with Unity Interception and Policy Injection:
- INotifyPropertyChanged AOP
- IDataErrorInfo AOP
- Policy Injection
- Performance and optimizations
- The final solution
I hope you will find this useful in your work; all feedback will be greatly appreciated.
The previous article discussed an implementation of the INotifyPropertyChanged
aspect using Unity Interception AOP. Today we will see how a similar approach can be applied to another interface commonly used by WPF (as well as by ASP.NET MVC).
The IDataErrorInfo
interface consists of two methods:
- an indexer accepting a property name (
columnName
) parameter and - an
Error
property.
We will solely focus on the indexer, which returns error messages on a per-property basis.
The Validation Application Block allows developers to easily incorporate input validation via property attributes and/or application configuration, supporting a variety of provided validators, as well as custom ones.
IDataErrorInfo
and VAB seem to be a perfect match, and have indeed been integrated. Adding Unity Interception will further simplify input validation, so that (presentation) models could be specified in the following manner:
[NotifyPropertyChanged, DataErrorInfo] public class Contact : MarshalByRefObject, INotifyPropertyChanged, IDataErrorInfo { [StringLengthValidator(1, 20, MessageTemplate = "First name length must be between {3} and {5}.")] [ContainsCharactersValidator("0123456789", Negated = true, MessageTemplate = "First name cannot contain digits")] public string FirstName { get; set; } [StringLengthValidator(1, 20, MessageTemplate = "Last name length must be between {3} and {5}.")] [ContainsCharactersValidator("0123456789", Negated = true, MessageTemplate = "Last name cannot contain digits.")] public string LastName { get; set; } public event PropertyChangedEventHandler PropertyChanged = delegate { }; public string Error { get { return null; } } public string this[string columnName] { get { return null; } } }
Note: The implementation presented below is limited to classes derived (possibly indirectly) from MarshalByRefObject
.