Page view counter

Data Binding – Data Validation

SLLogoWords

The third and final Data Binding topic I'd like to cover for now is Data Validation. I'll modify the code discussed yesterday we're going to validate the Quantity on Hand field, already marked as two-way (that is, the user can enter a new value and it is stored in the underlying business object – the current book).

 DataBindingArchitectureTwoWay

Our goal is to capture and handle two types of errors

  • Exceptions thrown from the Binding Engine
  • Exceptions thrown from the Binding Source

An example of an exception the Binding Engine would throw would be were the user to enter letters where an integer value is expected

Binding Source exceptions would be created by the author of the Binding Source class (the Book Class) to ensure data integrity. In our case, we might throw an exception if we are handed a negative value for Quantity on hand. Thus, we might modify the set accessor for Quantity on hand as follows,

 

   1: public class Book : INotifyPropertyChanged
   2: {
   3:    private int quantityOnHand;
   4:      // Snip 
   5:  
   6:    public int QuantityOnHand
   7:    {
   8:       get { return quantityOnHand; }
   9:       set
  10:       {
  11:          if ( value < 0 )
  12:          {
  13:             throw new Exception( "Quantity on hand cannot be negative!" );
  14:          }
  15:          quantityOnHand = value;
  16:          NotifyPropertyChanged( "QuantityOnHand" );
  17:       }       // end set
  18:    }
  19:  

To manage both of these types of errors need to take 3 steps

  1. Identify the error handler either in the control or higher in the visiblity hierarchy (e.g., a container; in this case the grid that contains the text box)
  2. Set NotifyOnValidationError and ValidateOnException to true. The latter tells teh Binding Engine to create a validation error event when an exception occurs. The former tells the Binding Engine to raise teh BindingValidationError event when a validation error occurs.
  3. Create the event handler named in step 1

Identify the Handler

We'll put the identifier of the handler in the grid so that it may be shared by all the controls within the grid.

<Grid x:Name="LayoutRoot" Background="White" BindingValidationError="LayoutRoot_BindingValidationError" >

Set NotifyOnValidationError and ValidateOnException

These are set as part of the binding syntax in the control itself,

   1: <TextBox x:Name="QuantityOnHand"   
   2:     Text="{Binding Mode=TwoWay, Path=QuantityOnHand, 
   3:         NotifyOnValidationError=true,  ValidatesOnExceptions=true }"
   4:     VerticalAlignment="Bottom"
   5:     HorizontalAlignment="Left"
   6:     Height="30" Width="90"
   7:     Grid.Row="4" Grid.Column="1" />

Create the Event Handler

The event handler named in the grid is implemented in the associated code-behind file,

   1: public partial class Page : UserControl
   2: {
   3:    private bool clean = true;  // new flag
   4:  
   5:    void Change_Click( object sender, RoutedEventArgs e )
   6:    {  // if not clean, don't change books
   7:       if ( !clean )
   8:          return;
   9:       // snip
  10:    }
  11:  
  12:    private void LayoutRoot_BindingValidationError( 
  13:       object sender, ValidationErrorEventArgs e )
  14:    {
  15:       if ( e.Action == ValidationErrorEventAction.Added )
  16:       {
  17:          QuantityOnHand.Background = new SolidColorBrush( Colors.Red );
  18:          clean = false;
  19:       }
  20:       else if ( e.Action == ValidationErrorEventAction.Removed )
  21:       {
  22:          QuantityOnHand.Background = new SolidColorBrush( Colors.White );
  23:          clean = true;
  24:       }
  25:    }

Delegation of Responsibility

Notice the careful delegation of responsibility. 

The Binding class knows that it is handling validation and some first approximation of validity (integers aren't text) but it turns to the Book class for further validation (e.g, Quantity on Hand can't be negative). If it finds that the value is invalid it raises an event, but it is up to the UI to handle that event and decide how to display that there is invalid data to the user.

Page.xaml in this case manages that by refusing to move to the next book and turning the input box red. There are a thousand other things it could do, but the key here is separation of responsibility. The UI doesn't know why the data is invalid, only that it is.

Here is what it looks like when you enter invalid data and hit the Change Book button

InvalidData

As you can see, the entry box turns red, and the book does not change until the user fixes the data entered.

For those of you who want to copy and paste, here are all the changes

// page.xaml.cs

private bool clean = true;


private void LayoutRoot_BindingValidationError( 
   object sender, ValidationErrorEventArgs e )
{
   if ( e.Action == ValidationErrorEventAction.Added )
   {
      QuantityOnHand.Background = new SolidColorBrush( Colors.Red );
      clean = false;
   }
   else if ( e.Action == ValidationErrorEventAction.Removed )
   {
      QuantityOnHand.Background = new SolidColorBrush( Colors.White );
      clean = true;
   }
}



// page.xaml

<Grid x:Name="LayoutRoot" Background="White" BindingValidationError="LayoutRoot_BindingValidationError" >

<TextBox x:Name="QuantityOnHand"   
    Text="{Binding Mode=TwoWay, Path=QuantityOnHand, 
        NotifyOnValidationError=true,  ValidatesOnExceptions=true }"
    VerticalAlignment="Bottom"
    HorizontalAlignment="Left"
    Height="30" Width="90"red
    Grid.Row="4" Grid.Column="1" />


// book.cs

public int QuantityOnHand
{
   get { return quantityOnHand; }
   set
   {
      if ( value < 0 )
      {
         throw new Exception( "Quantity on hand cannot be negative!" );
      }
      quantityOnHand = value;
      NotifyPropertyChanged( "QuantityOnHand" );
   }       // end set
}
Published 13 October 2008 12:30 PM by jesseliberty
Filed under: ,

Comments

# party42 said on 13 October, 2008 03:03 PM

Jesse,

interesting read. Two questions though, is the base Exception object the appropriate object to be throwing? Any inherited object might be better?

Besides that, doing validation inside your object model. Doesn't that kind of bind your objects (your model) to a particular GUI. In other words, would that be an advised practice?

Regards, Nathan

# Data Binding ??? Data Validation said on 13 October, 2008 07:28 PM

Pingback from  Data Binding ??? Data Validation

# jiafeng said on 13 October, 2008 08:49 PM

Jesse,

Great article! Could you give an example how to do this with LinqToSQL class? They are automatically generated and implemented INotifyPropertyChanged but it only exposed property changed event, How do I modify its set assessor then?

Thanks, Jia

# 2008 October 14 - Links for today « My (almost) Daily Links said on 14 October, 2008 04:02 AM

Pingback from  2008 October 14 - Links for today &laquo; My (almost) Daily Links

# Silverlight news for October 14, 2008 said on 14 October, 2008 05:14 AM

Pingback from  Silverlight news for October 14, 2008

# party42 said on 14 October, 2008 08:02 AM

Jesse, are you also planning to talk about data integrity and concurrency issues?

We've run into some major issues regarding the sorta disconnected envirment silverlight is and its data being on a remote location.

To clarify, we have a SL app which stores its data both locally (for speed) and remotely (for obvious reasons). To access this data, the SL environment uses a webservice. This webservice is also publically available for hooking up to other clients. To keep the data in sync we use a "datelastmodified" (isdirty switch) on both data sources. Though checking this on every move a user makes takes time (about 1 second every time).

Ideally I guess having a full duplex service would be a solution but Im not sure if thats even possible with services. How would a service know its client...

That sounds scary anyway :)

# Data Binding in Silverlight said on 20 November, 2008 10:49 PM

Pingback from  Data Binding in Silverlight

# Data Binding in Silverlight with Jesse Liberty said on 24 November, 2008 03:35 PM

Pingback from  Data Binding in Silverlight with Jesse Liberty

# ??berblick Data-Binding at Programming with Silverlight, WPF & .NET said on 24 November, 2008 05:16 PM

Pingback from  ??berblick Data-Binding at Programming with Silverlight, WPF &amp; .NET

# Jesse Liberty - Silverlight Geek said on 25 November, 2008 11:40 AM

Happy to return to my monthly interview on the Sparkling Client podcast; this month discussing the fundamentals

# Microsoft Weblogs said on 25 November, 2008 12:28 PM

Happy to return to my monthly interview on the Sparkling Client podcast; this month discussing the fundamentals

# Validation of Data in Business Layer « Lamentations of one programmer said on 16 March, 2009 02:16 PM

Pingback from  Validation of Data in Business Layer &laquo; Lamentations of one programmer

# brauliod said on 02 May, 2009 12:40 PM

Nice and clean sample.

Only one thing, why the sample project is not available for downloading?

Thanks

 Braulio

# Jesse Liberty - Silverlight Geek said on 04 May, 2009 12:39 AM

Towards the end of my “ What’s New In Silverlight 3 ” presentation for Tech Ed, &#160; I discuss the

# Microsoft Weblogs said on 04 May, 2009 01:29 AM

Towards the end of my “ What’s New In Silverlight 3 ” presentation for Tech Ed, &#160; I discuss the

# Nice Links To Study « Jony ’s Weblog said on 14 May, 2009 09:03 AM

Pingback from  Nice Links To Study &laquo; Jony &#8217;s Weblog

# Top-silverlight » Blog Archive » Validation. Hey! You???re Done! said on 03 June, 2009 04:28 AM

Pingback from  Top-silverlight  &raquo; Blog Archive   &raquo; Validation. Hey! You???re Done!