Best practices on validation and use of ErrorProvider

Feb 28, 2008 at 3:46 PM
First, this article has been informative read for me:

http://www.pluralsight.com/wiki/default.aspx/Craig/WinFormsValidationBroken.html

I've decided on this approach on forms I am doing validation on:

1. Do per control validation (to respective properties of bound business object) and use ErrorProvider to signal user.
2. Do a comprehensive validation in the OK handler to stop user from closing the form while data is invalid.
3. Do CancelEdit (implemented IEditableObject on business objects) in Cancel handler to return bound business object data to (previous) valid state.

I like not having to lock the user from navigating controls on the form while data is invalid, but allowing OK handler to prevent them from closing the form.

Some questions:

- How to implement a generic handler for #1 above. In other words, define on OnValidating event handler to be shared by all controls to be validated. The problem I run into is trying to pull the appropriate property name to call PropertyValidationManager::ValidateProperty() and if not valid, then call PropertyValidationManager::GetResultsInErrorForProperty. One thought was to place this information in the control's Tag property. Is this a good way to do this?

- Do I need to create an ErrorProvider instance for each control that I am validating? This seems a little redundant.

Anjo
Feb 28, 2008 at 8:40 PM
Ok did some reading and testing, am now using NotifyValidatableBase for the base class of all my business objects. Using one error provider object on each form, with the DataSource set to the form's bound business object.

This is a great framework to work with, so far love everything I've used!

Anjo
Feb 28, 2008 at 10:48 PM
Anjo

Glad you worked it out.

A couple of things to note.

-You will sometime need more than one ErrorProvider on a form. The reason is that you need one ErrorProvider per DataSource. So if you have multiple (different) objects being validated on one form you will have an ErrorProvider and a DataSource for each of the objects.

-There are examples of how all this works in the quickstarts. Just set QSWindowsApplicationCSharp as the startup project and run the solution
Was there any outstanding questions?

Oct 27, 2009 at 11:38 PM

Simon,

 

Revisiting this topic and have a corollary question to your most recent post (2008-02-28):

Definitely I will require multiple ErrorProvider objects for multiple different objects being validated on one form.

However, are there any shortcuts to this if the multiple different objects are nested?  e.g. Class A holds Class B.  A has properties that have validation rules (A::Prop1, A::Prop2), as does Class B, B:Prop1, B::Prop2, etc..  A also holds an instance of B as a property as well A:PropB.

My form code accepts an object of Class A and sets up bindings.  Note that Windows Forms bindings allows binding to nested properties, so I can bind interface objects to A::PropB::1 by settings datasource to A and dataMember to "PropB.1".

Now when I go to set up the ErrorProvider:

errproA->DataSource = A;
A->PropertyValidationManager->ValidateAllProperties();

This will do appropriate error icons for bound properties of A, but not of A::PropB.  Is the only workaround to create a separate ErrorProvider for B?  There seems to be some interaction here with data binding - I can't just set errProB datasource to A->PropB and be done with it, it seems I have to change the bindings associated with properties of B, i.e. datasource must be PropB, not A, and dataMember now becomes "1" instead of "PropB.1".

Any help appreciated, especially since this could get particular nasty/verbose given my highly nested object heirarchy.

A question that came up was does validation itself nest?  i.e. in calling ValidateAllProperties, does the framework know to nest into PropB and run those validation rules on its properties?  Do I need a special attribute on A::PropB to flag this?

Anjo

 

Oct 27, 2009 at 11:43 PM
Edited Oct 27, 2009 at 11:43 PM

2 minutes after posting this I realized the following:

errProB->DataSource = A;
errProB->DataMember = "PropB";

Now this solves the problems of not having to modify all my data bindings which use A as the DataSource and a nested DataMember "XXX.YYYY.ZZZZ".

Question still remaining - any way to use one ErrorProvider if all the objects are nested into one and does Validation itself nest into objects?

Anjo

Oct 28, 2009 at 8:05 PM

This one took me a little longer, but it is the case that this framework supports validation of child properties, specifically the help file (.chm) refers to this as "heirarchial validation".

This thread was what illuminated me:
http://validationframework.codeplex.com/Thread/View.aspx?ThreadId=52087

Adding a ValidatableRuleAttribute cleared this up.  A sub question is if ValidatableRuleAttribute::UseErrorMessages is false, what error message is generated?

Corollary, does the fact that heirarchial validation can occur mean that I can fall back to using one ErrorProvider on a form if all the various objects are held within the same heirarchy?

Anjo

P.S. Thank you for this framework, it is a lifesaver and very feature rich, looking forward to where it continues to go.

Oct 28, 2009 at 8:23 PM

To answer my own question again, when UseMemberErrorMessage is false (I typoed it above btw), the error message is "The property 'XXXXX' is invalid."  How to change this?  I'm fuzzy on attribute usage (named parameters have an order?), but it seems you have to do:

[ValidatableRuleAttribute( UseMemberErrorMessages=false, ErrorMessage="xxxxxxxx")]

A documentation suggestion:

ValidatableRule is not listed in the help documentation in the "Adding Validation Rules using Attributes" topic.  It would be helpful to see it there.

Thanks!