Simplest way to do Validation in WPF is usually implementing interface, and do the validation in the indexer’s getter. It turns out to be ugly and gets out of hand when your model / viewmodel gets a little larger.
Implementing it is as simple as this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
publicstringthis[string propertyName] { get { //Validate property that is being set, //and return an error message if there's //any error.
returnnull; } }
publicstring Error { get { returnstring.Empty; } }
I intend to use NHibernate Validator attributes to add non-intrusive validation to my ViewModel classes. So you’d just decorate properties of your ViewModel and let WPF and NHibernate Validator do the rest for you. Before we do that, let’s create a more elegant way to show the errors by restyling the TextBox control and add an Error Icon and tooltip to it in case of an error existing:
Now that styles are all set, let’s configure NHibenrate Validator’s engine on application startup. Nothing fancy, just a straightforeward configuration. We’ll use a shared validation engine:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
publicvoidRegisterValidatorEngine() { var config = new NHVConfigurationBase(); config.Properties[Environment.ApplyToDDL] = "false"; config.Properties[Environment.AutoregisterListeners] = "true"; config.Properties[Environment.ValidatorMode] = "UseAttribute"; config.Properties[Environment.SharedEngineClass] = typeof(ValidatorEngine).FullName; config.Mappings.Add(new MappingConfiguration(DomainAssemblyName, null)); Environment.SharedEngineProvider = new NHibernateSharedEngineProvider(); Environment.SharedEngineProvider.GetEngine().Configure(config); ValidatorInitializer.Initialize(NHibernateConfig); }
And to make things reusable, why not create a base ViewModel:
publicabstractclassValidatableViewModel : { privatereadonly ValidatorEngine validation; protectedValidatableViewModel() { validation = Environment.SharedEngineProvider.GetEngine(); } publicstringthis[string propertyName] { get { var rules = GetInvalidRules(propertyName); if (rules != null && rules.Count > 0) { return rules[0].Message; } returnnull; } } publicstring Error { get { returnstring.Empty; } } public IList<InvalidValue> GetInvalidRules(string propertyName) { var type = this.GetType(); return validation.ValidatePropertyValue(type, propertyName, GetPropertyValue(type, propertyName)); } public IList<InvalidValue> GetAllInvalidRules() { return validation.Validate(this); } privateobjectGetPropertyValue(Type objectType, string properyName) { return objectType.GetProperty(properyName).GetValue(this, null); } }
The rest is just to inherit the ValidatableViewModel and add necessary attributes to our binded properties. A sample ViewModel containing a Save command, which is invocable only when there’s no error on the model and a couple of other business properties would look like this: