пятница, 30 мая 2008 г.

Business Objects validation in WPF wizard

Oh dear! Is it really me writing? Well, yeah, it is me!

I had a lot of fun in Mediterranean yachting and now I am full of strength to manage with my thoughts' flow. =)

While writing this post I understood that I chose the very interesting theme to my mind - WPF wizard component development that I've done for my projects. But then I realized that it would take a year to highlight all the process with my speed of posting, so I came back to the original title and focused on the particular theme. I'll try to write on WPF wizard later on, but to keep your interested I'm going to include wizard's sources.

As I've mentioned in my previuos posts on DM-V-VM pattern I don't edit objects in most of UIs. The reason is simple - ViewModel doesn't track edited object state. I do it in wizards. WPF doesn't contain such a useful component as a wizard by default so you have 2 ways out: 1st - pay someone for ready custom component and the 2nd one - write your own. I chose 2nd one =) as I often did. It was a very big work that brought tons of difficulties and challenges but was a lot of fun to solve. Propably the biggest challenge was UI integration in validation process where UI could track underlying objects' state and react respectively avoiding user from saving objects in an inconsistent state. I knew about validation in WPF binding, but it was not quite the thing I needed. (In WPF that goes with .Net 3.5 business objects validation can be plugged in validation process easily by using ValidatesOnError binding property and IDataErrorInfo interface in object, but still it is not quite one I needed). Karl Shifflet wrote a wonderful article on validation and WPF business applications developement generally, here it is: http://www.codeproject.com/KB/WPF/WPFBusinessAppsPartThree.aspx .

As an alternative to editing objects in wizard you can use this approach, which I've mentioned earlier.
So what do I need and what do I want?
I want:

  • UI to track underlying objects' state automatically and react respectively - buttons Next, Save should be disabled in case an underlying object is in invalid state; in other words wizard should not let you make a mistake;
  • developer writing wizard code to avoid taking part in validation process, in other words validation must start automatically in a transparent way, no code-behind with validation code;
I have:
  • Validation in WPF binding engine already exists. One can plug in by writing his own ValidationRule descendant. There also is a static class Validation that provide means to set ErrorTemplate for UI control and get errors collection. So why doesn't it fit our needs? The reason is simple - it validates the UI data - not underlying objects, but we need a unified process that will validate business objects decoupled from UI technology. Therefore we won't use WPF validation as a main engine, but only as an extensibility point;
  • Validation Application Block (VAB), that was developed to validate objects, can be found in Enterprise library (EL);
  • There is command notion in WPF that can control UI state. I wrote about'em in previous posts.
Well, it seems that we have all we need! So let's go on.

First of all let's check out this scenario: we've got a wizard that edits a human/visitor (whatever) entity.

  1. you fill in first name, last name and other fields at wizard's first page, and the first name field is mandatory.
  2. you provide an entity with the access data such as login, password and password confirmation in the second page;
  3. you fill all the blahblahblah fields in the rest of a wizard's pages... =)

Entity you edit in my wizard is applied to DataContext property, thus enabling all the visual tree (pages with controls in it) to inherit the last one.

Every UI control, which triggers some action, is bounded with a command. Every command is wrapped in alreasy
familiar CommandModel class. Said models are holding command's state and execution logic. And what I intend to do is to delegate them validation.

First I used to delegate validation logic to my domain objects (you can read about this approach here) but it made my wizard control tightly coupled with my domain model, which is ugly! So I've changed a direction and made my commands validating edited entities. I use Validation Application Block from Enterprise Library. David Hayden has a tons of tutorials on p'n'p's products, including this set of articles on VAB, so I won't write on how VAB is working because you can read everything there.

Wizard edit process is divided into pages that holds some logical associated data, and this logical association correlates with ValidationRuleSet notion, so every WizardPage carries a RuleSet property, that must be set on developement stage.

When it comes to validation I simply call VAB's facade to do the work.

Here is what our visitor class might look like:

You see it has a property Name that is marked with StringLengthValidator attribute [1;200) with the CommanRuleSet ruleset name, and wizard page that edit this property must have the same ruleset name.

Now, when we finished with validation we can start writing our commands logic.
I have the following commands in wizard:
  • NextPage - a command that transfers you to the next page;
  • PrevPage - a command that transfers you to the previous page;
  • GoToPage - a command that performs a gap to the specified number of pages;
  • Save - a command that triggers Finish event;
  • Cancel - a command that triggers Cancel event;
  • Help - a command that shows a user manual;
I'll make an example with the NextPage Command. Command checks whether an entity is valid with corresponding ruleSet, and whether the current page is not last and whether this page is not marked as invalid by WPF Validation manager (it is the extensibility point):

This logic will be called automatically by WPF CommandManager and will reflect state of edited object on NextButton button.

Extensibility point.

Imagine a following scenario:

you edit a credential object that is formed by a Login and Password properties. You have 1 TextBox - Login, and 2 PasswordBoxes - for Password and PasswordConfirmation. This credential object (lets call it LoginCredential) is in DataContext property of wizardpage. You have binded TextBox's Text property to a Login property of credential, text from first PasswordBox use assing to Password property of credential in code-behind. However, in order to validate a password you need user to confirm it and a LoginCrredential class doesn't have such a property (PasswordConfirmation) and never have to! How we will keep our Buttons' state syncronized wth data, when they should be inactive unless user has confirmed his password?

Well, here is the place where I plug in a WPF validation process. In this case I don't need to validate business object's data and should validate only that part of data, which is located in UI.

I've written a ValidationHelper class to streamline my validation code.

There is an attachable property Bag, which can be attached to any DependencyObject and bound with some data (it is useful when you have no properties to bind).
Back to our scenario you'll have to bind ValidationHelper.Bag on first PasswordBox to Password property of underlying credential. You have to do this because in PasswordBox a Password property is not a dependency property (I know that there is a security issue with my attached property take it as an example).

The key element in integration is the PasswordValidationRule that can be seen in the picture above. It is a custom descendant of WPF ValidationRule class. I had to do some code-behind here because, as I've mentioned earlier, Password is not a dependecy property. In this code-behind I obtain binding expression for ValidationHelper.Bag property and force it to update source, thus forcing validation.

I need to send PasswordCopy and WizardPage objects from UI into my ValidationRule object that is not a DependencyObject and even isn't in Logical or VisualTree. What we need to do is to attach virtual branch to the LogicalTree and this problem was perfectly solved by Josh Smith. You can read about this approach in his article. Here’s a brief description. ValidationRule is not a descendant of DependencyObject class so you can't bind its properties, but you can write a surrogate DependencyObject descendant class that will keep one dependency property that can be bound with data. This data is being sent into the dummy holder in resources (DataContextBridge) by means of OneWayToSource binding. After that you can bind a surrogate object Value property to DataContextBridge.

The only thing that left is to write code for ValidationRule. It compares original password string with its copy and mark a wizard page as invalid in case passwords are not identical:

There are two methods in ValidationHelper - MarkInvalid and ClearInvalid that are simply wrappers around WPF Validation class. All that is required to make UI element compatible with ValidationHelper is to attach ValidationHelper.Bag property and bind it with itself (as it is done in WizardPage's default style).

Well, here we are - our validation process in wizard is ready.

In a simple scenario all that developer will have to do is to mark entities with validation attributes, or even configure 'em in enterprise library configuration tool and nothing else. All the rest work will be done by wizard automatically absolutly in an absolutely transparent manner.

Good luck!

P.S. sources are coming on a little bit later.

1 комментарий:

Arifur Rahman комментирует...

Can you please send me the source code at arrahman@ael-bd.com