ValidatableBase: Back to the drawing board
A couple of weeks ago I posted about my new ValidatableBase object I put on GitHub. It worked pretty good for Windows Universal Apps and I'm enjoying it's simplicity.
I ran in to some drawbacks when using it with WPF however. In WPF, most projects use either IDataErrorInfo or INotifyDataErrorInfo. Neither of these two interfaces worked for the business requirements I have. Neither interface make it really easy to break up your validation errors in to categories. What if want to perform validation and have it come back with a warning instead of an error? You can't do that with IDataErrorInfo and while you can do it using INotifyDataErrorInfo, it requires a decent chunk of plumbing to expose and doesn't make sense semantically. To get all errors, warnings and information messages, you access the GetErrors method or HasErrors property. It makes things confusing when building a framework and you want others to access warnings and informative messages from the model. "Just grab the warnings from the GetErrors method". Huh?
So I thought I'd just move over and ValidatableBase in WPF. The problem that I ran in to with it is that it was not easy to quickly re-evaluate a properties failed validation. I can of course re-run the entire validation process, but I wanted to have more control. Since the Func< > required by the ValidateProperty is typically an anonymous method or a private method within the model, it makes invoking the ValidateProperty method on the model really unsafe. The view model was reproduce the validation rules for the property, which it shouldn't ever do. If I exposed all of the individual validation methods within the model, then I kind of feel like I'd be breaking the Open/Closed principle.
To resolve this, I set out to re-build the ValidatableBase with a better version (still a work-in-progress). The revision will provide support for two methods. ValidateAll()
and ValidateProperty(string property)
. These two methods wil then hit a cache of Validation Rules that each object has associated to it's properties and run the validation from those objects. As an example, I can create a StringIsNotNull validation rule object and add it via a property. When a model is instanced, it wil find all of the validation rules required and cache them. When either of the aforementioned validation methods are invoked, the applicable validation rules will get their Validate()
method called and your property will be validated. If you want to re-evaluate a property, you can with ValidateProperty("Email");
. This lets you abstract the actual validation rules out in to independent objects that can be re-used across your models.
The work is mostly done, but I'm having to spend some time determining the best way to provide parameters to the validation rules. Once this is ironed out, I should be able to publish a new version to GitHub.