Validation. Hey! You’re Done!

 

Towards the end of my “What’s New In Silverlight 3” presentation for Tech Ed,  I discuss the (much anticipated) enhanced Data Validation in SL3.  Now, anyone who has been around the block a few times knows that there are a lot of different ways to handle data validation, and that each framework offers a different approach (not that long ago the approach was summed up as “hey, you’re a programmer, you want data validation, write some.”)

error1

error3

Plus Ca Change, plus c’est la meme chose

In October I wrote a blog entry about Data Validation in Silverlight 2.  It is interesting to look back at it now and realize that what has changed is not the use of the binding engine, setting the mode to two way, or even setting NotifyValidationError=true andValidationExceptions=true. All that was true back in October.

What has changed is that back in October, we wrote the code to manage everything about the validation – not only the business logic (which is to be expected and desired) but the entire UI for managing the error notification:

olderrorcode

From Hand Coded To Toolable Visual State

ValidationStates

The key innovation in Silverlight 3 is to tie error handling into the Visual State Management of the control. We are used to the fact that all the standard controls have two state groups: the CommonStates and the FocusStates. To these we now add three ValidationStates,

What is more, a number of input controls (TextBox, CheckBox, RadioButton, ListBox, ComboBox and soon PasswordBox) already have default storyboards for transitioning into these states (as you’ll see in just a moment

This means that right out of the box these controls know how to respond to invalid data, where the validity is determined by the object to which they are bound. Sweet.

Writing The Code

Let’s start simple, using the out-of-the-box capabilities, and then in a subsequent post I’ll look at how a little templating can give you much finer control over the interaction with the user.

To make this work you need the following:

  • A form with a way for the user to provide input (we’ll use a text box)
  • A data object to bind the input control  to
  • A user to enter incorrect data

Here is a picture of the form, displaying the error message that is caused by entering an invalid ISBN (one that has the right number of digits but where the checksum does not compute correctly):

checksumInvalid

We’ll support two other errors as well (not the right number of digits, and invalid values)

InvalidLength

invalidValues

Start With The Data

What I like most about this model is you start with the data, not the UI. You begin by designing your data object, and what validity checks you want.  I’ll post the code right after Tech-Ed, but I start with a Book class that implements INotifyPropertyChanged in the normal way. Then I added to the property for the ISBN my validation checking, throwing an exception if it is invalid in any way. The text I put in the exception is the text that shows up in the error message.  Here’s the ISBN10 property:

public string ISBN10
{
get
{
return isbn10;
}
set
{
if ( value.Length != 10 )
{
throw new ArgumentException( "Must be exactly 10 integers long" );
}

char[] isbnAsArray = value.ToCharArray();

foreach ( char c in isbnAsArray )
{
if ( ( !Char.IsNumber( c ) ) && c.ToString().ToUpper() != "X" )
{
throw new ArgumentException( "Must be numbers or letter X" );
}
}

int runningTotal = 0;
for ( int i = 0; i < 9; i++ )
{
int val = ( Convert.ToInt32( isbnAsArray.ToString() ) * ( 10 - i ) );
runningTotal += val;
}
int mod = runningTotal % 11;
int checkSum = 11 - mod;

int isbnCheckSum = -1;
if ( isbnAsArray[9].ToString().ToUpper() == "X" )
isbnCheckSum = 10;
else
isbnCheckSum = Convert.ToInt32( isbnAsArray[9].ToString() );

if ( isbnCheckSum != checkSum )
{
throw new ArgumentException( "Checksum is invalid!" );
}

isbn10 = value;
NotifyPropertyChanged( "ISBN10" );

}
}

[ Checksum computation from Wikipedia. ]

From Data To DataBinding

Once you’ve created your data object, you can build the UI around it, and bind the display objects to the properties of the data object. I decided to create the page in Blend, making it absurdly easy to lay out the rows and columns and to define the style for the prompt and for the data entry text box.

BlendValidation

I could have assigned the visual state, etc. inside Blend, but since I wasn’t changing anything, but rather just using what is already provided I saved this and clicked on Edit In Visual Studio. I then added the binding for the Title and Author by hand,

<TextBox x:Name="Title"
Grid.Column="1"
Grid.Row="1"
Text="{Binding Title}"
Style='{StaticResource Input}' />
<TextBox x:Name="Author"
Grid.Column="1"
Grid.Row="2"
Text="{Binding Author}"
Style='{StaticResource Input}' />

And followed that by adding the binding for the ISBN which required just a couple extra properties, but, you’ll notice, the same properties discussed in the October article and shown above,

<TextBox x:Name="ISBN10"
Grid.Column="1"
Grid.Row="3"
Style='{StaticResource Input}'>
<TextBox.Text>
<Binding Mode="TwoWay"
Path="ISBN10"
NotifyOnValidationError="True"
ValidatesOnExceptions="True" />
</TextBox.Text>
</TextBox>

That’s it! the rest just works.  No, really.

One Little Extra

Alright, if you want to get fancy; the text box doesn’t update and check the validity of its contents until you tab out (how else can it know when you’re done?). Cribbing from Karen Corby’s presentation at Mix I added a button to attach the UpdateSource() method of BindingExpression onto, and while I was at it, being amazingly lazy, I added a button that puts in the real ISBN for Death In Venice (one does get tired of typing the same thing while debugging!)

Here’s the Xaml,

<Button x:Name="FillButton"
Content="Fill Textbox With valid ISBN 10"
Width="200"
Height="25"
FontSize="14"
Grid.Column="0"
Grid.Row="4"
Margin="5"
HorizontalAlignment="Right" />

<Button x:Name="ValidateButton"
Content="Validate Now!"
Background="Green"
Width="120"
Height="25"
FontSize="14"
Grid.Column="1"
Grid.Row="4"
Margin="5"
HorizontalAlignment="Left" />

and here’s the code-behind for the buttons,

void ValidateButton_Click( object sender, RoutedEventArgs e )
{
// BindingExpression requires using System.Windows.Data
BindingExpression bindingExpression =
ISBN10.GetBindingExpression( TextBox.TextProperty );
bindingExpression.UpdateSource();
}

void FillButton_Click( object sender, RoutedEventArgs e )
{
ISBN10.Text = "0141181737";
}


womc900

This code was compiled with Silverlight 3 – Which is a beta product!  For more on this guarantee, please see this page.

About Jesse Liberty

Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen online courses. His latest book, Building APIs with .NET will be released early in 2025. Liberty is a Senior SW Engineer for CNH and he was a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Microsoft MVP.
This entry was posted in z Silverlight Archives. Bookmark the permalink.