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
}

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.