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.

Screenshot of the example application

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(,)] or your own custom validation attributes.

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:

  1. 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
  2. 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:

  1. create an ‘IsValidated’ property which returns !HasErrors;
  2. bind it to the IsEnabled property of a control in the Xaml view; and
  3. 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:

  1. the class inherits from Screen so it can provide the functionality for a CM application easily;
  2. 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

Information and Links

Join the fray by commenting, tracking what others have to say, or linking to it from your blog.


Other Posts

Write a Comment

Take a moment to comment and tell us what you think. Some basic HTML is allowed for formatting.

Reader Comments

[…] 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 […]

Hi nice article :)

How can you stop firing these validations on the screen load. For example say the user wants to start a fresh data entry and he doesn’t want the validation errors appearing even before he types something.

Thanks in advance.

One of the challenges of WPF I find is that the error reporting mechanism is buried. It relies on the values of attached properties defined in the System.Windows.Controls.Validation class. The properties attached to controls are set by the notification mechanism.

For example, if you never call CM NotifyOfPropertyChange() method for a view model property which is bound to a property of a control defined in your view’s Xaml then errors will not be displayed.

So I suspect you need to suppress calls to NotifyOfPropertyChange() until you really want errors to appear. May be use a flag or something to disable calls until the screen is displayed.

What about validation in Silverlight? The bool IsValid method is not existing in SL.Could your code be used in SL too? Whar has to be changed?

In principle, yes, it should be possible to use it in Silverlight. I gave up using Silverlight 18 months ago when Microsoft made it clear there would never be cross platform support for it so I’ve never tested the idea.

This relies on overriding the CM Shell and checking a properties value against the set of ValidationAttribute instances decorating a property.

If validation attributes exist in Silverlight it should work.

Or are you saying that IsValid is not a member of ValidationAttribute in Silverlight? If so it would not surprise me. The idiotic and needless changes to WPF classes as they appear in Silverlight is one of the reasons I stopped using Silverlight.

When I add this to my solution some properties on the XAML window no longer work (WindowStyle=None). Can you look into this please?

Never mind, I figured it out. I was exporting the wrong type in one of my child controls.

I found your article from the Caliburn.Micro codeplex discussion forums. Are you still using the ValidatingScreen? If so, have you made any updates in the past year?

Great work, btw!

I’ve checked the code provided and our use of the code. Apart from a few changes to accommodate error reporting, there are no differences. This means we’ve not updated since June/July 2011.

We do use the screen but… For the past year (and for the foreseeable future) there have been no plans to do further WPF work. We may have to update existing projects but it is unlikely that it will involve changes to this code.

Also, we have no plans to update the version of CM used.

Are you asking about changes for a specific reason?

I was asking about any possible changes mostly to ensure that I wouldn’t spend too much time re-vetting anything out you may have already.

I still work on quite a bit of WPF and use Caliburn extensively; there are a few Validation routines around, but this one fits nicely with Caliburn.

It would be great if this could be built out a bit further (additional validators) and made into a CodePlex or Github project.

Hi,
Is there any chance how could I validate comboBoxes?
Cause CM automatically bind name of ComboBox with Selected+nameOfCombobox property.

Thanks,
Evzen

Thank you very much for your solution. I like it. I have a problem though. When I applied your solution for my project, I noticed that the textbox content is validated on ChangedProperty, and when I am trying to make it get rebound on LostFocus like this:
,
it stops validating. I mean it stops displaying the error message, though NoValidationErrors is set correctly, so the Save button with IsEnabled bound to it disabled in case of invalid input. If I don’t use explicit binding (just using Caliburn Micor naming convention), everything works.

David, if the validation stops working it means Caliburn is not sending notifications. Caliburn has configuration options it uses to determine the events it will fire and track when working with control types (different controls have different events which need to be fired). If you’re doing something unusual it may be Caliburn is not bound to the event. The Caliburn configuration is soft so you are able to override it (though now I don’t recall how). I can’t help further because the example I think you intended to provide did not come through. For example it may be that you’ve assumed you are sending focus back to the text box but in fact the focus is on one of the myriad parts that make up a text box control.

Thank you for answer. I will try again to post the piece of code that didn’t get though previously, I will just omit angle brackets: TextBox x:Name=”Url” MaxLength=”255″ Text=”{Binding Url, UpdateSourceTrigger=LostFocus}”
Grid.Row=”11″ Grid.Column=”1″ Style=”{StaticResource DetailTextBox}”

I think the “problem” is that you are binding to a Url control and expecting validation on the textbox. However as far as WPF and Caliburn are concern the validation is going to be on Url after all that’s the property which is ultimately changing. The textbox is just a vehicle for that change. At least I see a no validation taking place when the Text property of a text box control is bound to a dependency property.

A way you might accomplish what you want it to use the Caliburn ‘cal:Message.Attach’ syntax to capture the event in the view model and do something explicit with that event. In one of our applications we want to be able to capture the LostFocus event

cal:Message.Attach=”[Event LostFocus] = [Action LostFocus($source)]”

LostFocus is a method on the view model and $source is a reference to the control which generated the event. This method can then call the validation methods directly. Not exactly elegant but may get the job done.

Thank you again. I just wanted to say that I don’t use a Url control, it is just a regular TextBox. And this problem happens on any control that I bind explicitly. Sorry, I don’t understand the explanation of the problem (of course, I blame only myself for that)…

I am able to reproduce the problem. It’s occurring because the text property is bound. For some reason when this property is bound the TextChanged (or any other) event is fired. It’s not because of the use of UpdateSourceTrigger but because the Text property is bound. Maybe Eisenburg will be able to help you understand why.

Thank you very much for your help. Sorry for my ignorance, but how is Eisenberg?

Could you please tell how I can validate multiple controls, e.g. if I need at least one of three textboxes to be not empty, i.e. to report an error if all three are empty? Thanks.

By default all controls will be validated according to the declarative rules you have specified. So if one of your controls fails you are able to set, for example, an OK button based on the result of calling HasErrorsByGroup().

In my case I have a “CanSave” property guarding a button (x:Name=”Save”) which returns the value of HasErrorsByGroup to determine if this button is enabled.

As often it will be necessary to break controls into validation groups. In this case the validation rule can include a groupname. This allows you to call HasErrorsByGroup([groupname]) to test the validity of a logical group of contols: say, a single page of controls.

Thank you very much for your answer. But in my case, it is valid for one or two of multiple textboxes to be empty. It is invalid only if all three textboxes are empty.

But the principle applies. Each textbox will be it’s own group, say “tb1″, “tb2″ and “tb3″. Then in the “Can” guard property of the the control which must be enabled there will be code this reads something like:

return HasErrorsByGroup(“tb1″) || HasErrorsByGroup(“tb2″) || HasErrorsByGroup(“tb3″);

You could make it more elegant by implementing it in the framework. You would add a new property to the IValidationControl interface called, say, “Any”. Then implement this property in the validators and update the implementation of HasErrorsByGroup() to return true if *any* member of a group is valid.

Thank you very much.

Hi, would you be so kind to answer one more question?

I am trying to use this validation method, to apply required field rule, but because of some reason the initial input is considered as invalid, though my textbox has text in it, and ErrorContent is empty.

Maybe you have any idea why it is invalid?
Thanks.

David, it will depend on how you are assigning the default text and how you have defined the binding on the text field. There’s an example of pre-setting a text field in the example project. The password is pre-set and does not set off alarms.

If the arrangement of you code is such that the model’s dependency property is not called, the relevant validation function will not find a value. If a value is required then it will display an error.