Wednesday, October 10, 2007

LINQ to Controls (Validation)

For my next trick... I'll tack in a validator object into controls in my form and then call that object in a LINQ query to tell me if the input is valid. This is not the best way to accomplish this specific task, but I'm trying to keep my examples fairly simple and this should be easy to grok.

First, I create a class that can call a validation delegate.

class InputValidator
public delegate bool ValidationDelegate( Control ctrl );
private ValidationDelegate validateCode;
private Control _ctrl;
public InputValidator( Control ctrl, ValidationDelegate validate )
_ctrl = ctrl;
validateCode = validate;
public bool IsValid()
return validateCode( _ctrl );

Then, in the form initialization section, I'd assign the code to do the validation to the Tag property. If I were really wanting to creating an elegant validation solution that went beyond the Validating event of Control, I'd probably create extension methods/properties and tack them onto Control rather than using the Tag property. But let's keep our scope small.

textBox1.Tag = new InputValidator( textBox1,
delegate(Control ctrl) { return ctrl.Text.Length >= 5; } );

As delegates, the validation code can either be written for each control using anonymous methods, or shared between controls by creating a method with the correct signature and passing in that named delegate.

So, for the query, we can query all the controls on the form, get the ones where the Tag object is of the proper type, then cast the tag object and call the validation code. In the following query, we are returning all controls that are invalid.

var InvalidControls = from ctrl in Controls.Cast<Control>()
where ctrl.Tag != null
&& ctrl.Tag.GetType() == typeof( InputValidator )
&& !( (InputValidator)textBox1.Tag ).IsValid()
select ctrl;

Once you have the query, just foreach over the IEnumerable<Control> list and perform coloring or whatever operations you want. You may want to just have the LINQ query returned from a function that can be called from many places.

No comments: