Easy property validation for Caliburn Micro
Caliburn Micro (CM) is a great, lightweight MVVM framework for WPF, Silverlight and WP7. While CM will enable Binding.ValidatesOnDataErrors if a view model implements IDataErrorInfo automatically, it does not provide any specific support for property validation.
This post is about an extension to CM which makes it possible, just by dropping a couple of ‘black-boxes’ into your application code and with only declarative ‘coding’ (you need to change the parent of the view model, decorate your view bound properties with validators and set the error template on your Xaml controls), you can have great validation and reporting in your application no matter how rough and ready it is.
An example project is also available so you can see how it works.
Update 2011-02-18
Added an example of validating a password entered using the PasswordBox
element. The main property of the PasswordBox, Password, is not a
dependency property so cannot be bound. This makes view model validation
non-standard and not amenable to convention binding employed by Caliburn.
Update 2011-02-19
Added the concept of validation groups. This allows, say, the enabled state of a close button to be controlled by some sub-group of a form’s properties while still allowing all validations to be active. It might be used to independently validate the properties on each page of a TabControl.
Update 2011-02-22
Added support for validating only when a guard property is enabled. By default the guard property is Can[PropertyName]. But the guard property a validation controller will use can be set explicitly.
Building the application
The application has been created using VS 2010 and .NET Framework 4.0.
If you’d like a version which uses .NET 3.5 (and a functioning copy of CM which works with .NET 3.5) email caliburnexample@lyquidity.com
To compile you will need to add a reference to Caliburn.Micro.dll and to
the Blend System.Windows.Interactivity.dll
Background
This example shows how property validation can be defined for any CM screen just by decorating the properties with ValidationAttribute instances such as [Required()], [Range(
The CM ConfigurationManager will enable validation if the model being bound to a screen implements IDataErrorInfo. However I think its fairly common, especially in quick and dirty application written to get a job done, that either:
- validation rules are defined in Xaml which means the model is no longer source of all logic for the form so model testing cannot cover all scenarios; or
- there’s a big, custom switch statement in the ‘IDataErrorInfo.Items’ property of the model.
ValidatingScreen
This example sub-classes the CM Screen implementation to provide a common class from which your view model can be derived. This new class, here called ‘ValidatingScreen’, adds the logic necessary to determine if a view bound property has been decorated with one or more validators and, if so, will test each validators IsValid(<propertyName>) method and return the corresponding error message if any validator is not valid.
This mechanism makes it really simple to validate property values and provide a corresponding validation failure message so WPF error templates will be activated automatically. There’s no need to mess around with IDataErrorInfo as it all done automatically. All you have to do is have your view model inherit from ValidatingScreen and decorate properties which are bound to your view.
For example, suppose there’s a view field to collect an email address which must be entered. You might create a view model class like (irrelevant details omitted):
public class MyViewModel : ValidatingScreen<MyViewModel>, IShell, IActivate, ... { ... [Required(ErrorMessage="Email is required")]; [EmailValidator(ErrorMessage="The format of the email address is not valid")] pubic string EmailAddress { get { return _privateEmailAddressMember; } set { _privateEmailAddressMember = value; NotifyOfPropertyChange(() => EmailAddress); } } }
Even the bulk of this example is boilerplate code. The relevant lines are the validation attributes decorating the EmailAddress property (Required and EmailValidator). With these declarations the ValidatingScreen implementation will ensure errors are raised when either condition is not valid. It will also ensure the corresponding message is returned by the IDataErrorInfo.Item property so WPF can report it.
Validators
Part of this simplicity is possible because of the validators used. The validators are instances of sub-classes of the abstract ValidationAttribute, a class introduced in .NET 3.5 mainly to simplify validation in ASP.NET MVC.
A ValidationAttribute instance performs much the same role as ValidationRule but can be declared on the affected property and so, importantly, are part of the view model. This means all unit testing can include the effect of validation errors.
The .NET Framework provides some example ValidationAttribute implementations such as the RequiredAttribute used in the example, and also the RangeAttribute, RegularExpressionAttribute and StringLengthAttribute.
A custom ValidationAttribute is easy to define and can be as complex as required. The EmailValidatorAttribute used in the example shows how simple it can be to roll your own validator. This example is lifted from Scott Guthries blog post which introduces this decorative style of property validation.
Importantly for me, a European, the base ValidationAttribute class supports localization. The exmaple above uses hard coded error messages. But when a ValidationAttribute instance is used to decorate a property the string to report can be defined in another class, for example a string resource, by using the option to specify a class and property from which the string should be retrieved. The view model of example application attached to this post shows this option being used.
Note: The ValidationAttribute class can also be used to decorate methods and method parameters but these two features are not supported by the ValidatingScreen implementation. You can still declare validators this way but they will be ignored by the ValidatingScreen class.
WPF ErrorTemplate
Generating an error and message is one part of the example. The other is reporting it in the view. The example uses the control error template created by Beth Massi in her post about displaying data validation messages in WPF.
In her article Beth creates a reusable template defined to be used as a static resource in Xaml which can then be applied as the Validation.ErrorTemplate for many controls.
In the example application the template is defined like:
<Style x:Key="myErrorTemplate" TargetType="Control"> ... </Style>
And is applied to a control style, here a TextBox, as:
<Style TargetType="TextBox" BasedOn="{StaticResource myErrorTemplate}"> ... any other style defintions ... </Style>
In the main Xaml then any <TextBox /> instances will report validation errors using the template. See Beth’s article or run the example to see how it looks. Of course you don’t have to stick with this visual you can create your own.
How does the ValidatingScreen class work?
When referenced for the first time (when your view model is created) static properties of the ValidatingScreen class create two collections: one a list of view model properties which have validation attributes decorating them; the other a list of the validators indexed by the respective property names. Here is are the static variable assignments:
static readonly Dictionary<string, Func<TViewModel, object>> propertyGetters = typeof(TViewModel).GetProperties() .Where(p => GetValidations(p).Length != 0) .ToDictionary(p => p.Name, p => GetValueGetter(p)); static readonly Dictionary<string, ValidationAttribute[]> validators = typeof(TViewModel).GetProperties() .Where(p => GetValidations(p).Length != 0) .ToDictionary(p => p.Name, p => GetValidations(p));
The class implements IDataErrorInfo (so you don’t have to). When CM enables validation errors on property bindings WPF will (and your unit tests can) call the IDataErorInfo indexer (C#) or Item method (VB) passing the name of the property for which the validation status is to be checked.
The indexer makes use of the property and validator lists (created when the ValidatingScreen class is first initialized) to perform the checks. It calls the IsValid() method of each validator attribute which decorates the property being tested and passes to the IsValid() method the current value of the property. If IsValid returns false the indexer implementation grabs the error message string by calling the validator’s FormatErrorMessage. All validators for a property will be tested and a collection of any error messages is returned from the indexer as one string with each error message on its own line.
public string this[string columnName] { get { try { if (propertyGetters.ContainsKey(columnName)) { var value = propertyGetters[columnName]((TViewModel)this); var errors = validators[columnName] .Where(v => !v.IsValid(value)) .Select(v => v.FormatErrorMessage("")); return string.Join(Environment.NewLine, errors.ToArray()); } return string.Empty; } finally { NotifyOfPropertyChange(() => this.Error); } } }
The class also implements the Error property of the IDataErrorInfo interface which is used to test all validators of all properties. Using the IDEI.Error property it’s possible to ignore the individual property validations and instead test all validations at the same time – perhaps before saving changes.
Because an application might not want a ‘save’ button to be active while there are validation errors, the ValidatingScreen class also implements a boolean property called HasErrors. This can be used to set the state of a property which is bound to the IsEnabled property of, say, a button control. The example application shows how this might implemented and is fairly trivial:
- create an ‘IsValidated’ property which returns !HasErrors;
- bind it to the IsEnabled property of a control in the Xaml view; and
- have all the view bound properties of the view model call NotifyOfPropertyChange(() => ‘IsValidated’ );
And this is how the example is implemented except the view model property is called NoValidationErrors not IsValidated.
References
The main idea for this example comes from this post on the Caliburn page on Codplex.
There are a couple of changes to this original post:
- the class inherits from Screen so it can provide the functionality for a CM application easily;
- the errors are reported using ValidationAttribute.FormatErrorMessage not ValidationAttribute.ErrorMessage because the former supports localization.
Beth Massi’s article about error templates
Download the example project




[...] Dev Blog – » Easy property validation for Caliburn Micro lyquidity.com/devblog/?p=71 – view page – cached Caliburn Micro (CM) is a great, lightweight MVVM framework for WPF, Silverlight and WP7. While CM will enable Binding.ValidatesOnDataErrors if a view model implements IDataErrorInfo automatically, it does not provide any specific support for property validation. Tags [...]