Dear visitor, thanks for stopping by! If you want, you can follow all updates on Snowball.be via RSS. You can also follow me on Twitter or Facebook. More interesting posts from other Microsoft Regional Directors can be found at The Region.
Gill Cleeren     .net | Silverlight | Silverlight Advent Calendar | sl4     December 18, 2009    

After looking at Twitter yesterday, we have arrived at another data binding-related feature new in Silverlight 4, namely the support for the IDataErrorInfo interface.

The fact that Silverlight supports this interface now, means we can fully use it to help with the display of validation errors in a data binding scenario. The interface itself is quite simple, as shown below:

public interface IDataErrorInfo
{
    string Error { get; }
 
    string this[string columnName] { get; }
}

When we are binding an object of a class that implements the IDataErrorInfo, Silverlight will automatically check each field for validation errors using the indexer. In here, we can write validation code that will check if the specified value is valid and if not, return the error message for that field. Silverlight will then automatically display the error for the field.

I have created a small sample that does exactly that. Being it almost Christmas, I have created a sample where the user can enter his christmas music collection, as shown below.

image

The type we are binding to is called ChristmasSong. This class implements both the INotifyPropertyChanged and the IDataErrorInfo interfaces. Both have been implemented in the code below. In the indexer, we are checking per column if the entered value is valid. If not, we are returning a message containing the validation error. Note that when we are entering “Last Christmas” by “Wham”, the application will not accept it! (Sorry to all Wham fans ;-) )

public class ChristmasSong : IDataErrorInfo, INotifyPropertyChanged
{
    private string title;
    private string performedBy;
    private TimeSpan duration;
    private DateTime published;
 
    private string error;
 
    public event PropertyChangedEventHandler PropertyChanged;
 
    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
 
    public string Title
    {
        get
        {
            return title;
        }
        set
        {
            title = value;
            NotifyPropertyChanged("Title");
        }
    }
 
    public string PerformedBy
    {
        get
        {
            return performedBy;
        }
        set
        {
            performedBy = value;
            NotifyPropertyChanged("PerformedBy");
        }
    }
 
    public TimeSpan Duration
    {
        get
        {
            return duration;
        }
        set
        {
            duration = value;
            NotifyPropertyChanged("Duration");
        }
    }
 
    public DateTime Published
    {
        get
        {
            return published;
        }
        set
        {
            published = value;
            NotifyPropertyChanged("Published");
        }
    }
 
    public string Error
    {
        get { return error; }
    }
 
    public string this[string columnName]
    {
        get 
        {
            string error = string.Empty;
            switch (columnName)
            {
                case "Title":
                    if(string.IsNullOrEmpty(title))
                        error = "Title can not be blank";
                    break;
                case "PerformedBy":
                    if(string.IsNullOrEmpty(performedBy))
                        error = "The artist should be filled in";
                    else if(performedBy.Equals("Wham") && title.Equals("Last Christmas"))
                        error = "You should NOT be entering that song to your collection!";
                    break;
                case "Duration":
                    if(duration.TotalSeconds > 600)
                    error = "A song can not be longer than 10 minutes";
                    break;
                case "Published":
                    if (Published > new DateTime(2010, 1, 1))
                        error = "You found a song from the future?";
                    else if (published < new DateTime(1900, 1, 1))
                        error = "That's a bit too old, isn't it?";
                    break;
            }
            return error;
        }
    }
}

We can now bind our UI to an instance of this type. Below is the XAML code for the Grid containing the fields. Note especially the data binding expression, where I’m stating the fields should be reporting the error back. For spacing reasons, I only pasted the Title field, the others are similar.

<TextBlock x:Name="TitleTextBlock" Text="Title" Grid.Row="1"  
  Foreground="Red" HorizontalAlignment="Left" Margin="2" 
  VerticalAlignment="Center"></TextBlock>
<TextBox x:Name="TitleTextBox" Grid.Row="1" Grid.Column="1" Width="200" 
  VerticalAlignment="Center" HorizontalAlignment="Left" Margin="2" 
  Text="{Binding Path=Title, Mode=TwoWay, ValidatesOnDataErrors=True, 
    NotifyOnValidationError=True}" />

When we are entering data now, the validation will kick in whenever a validation error is encountered.

We can take it one step further though, using the BindingValidationError event, defined on FrameworkElement. This event will trigger whenever a binding error is reported by the binding source, being here the instance of the ChristmasSong class. In this event, we can through the e.Action property check if an error was added or resolved. In this particular code, I have specified that the Submit button will only become enabled when there are no more errors.

private void ChristmasSongGrid_BindingValidationError(object sender, 
  ValidationErrorEventArgs e)
{
  switch (e.Action)
  {
    case ValidationErrorEventAction.Added:
         errorsOnPage++;
         break;
    case ValidationErrorEventAction.Removed:
         errorsOnPage--;
         break;
  }
  if (errorsOnPage == 0)
    SubmitButton.IsEnabled = true;
  else
    SubmitButton.IsEnabled = false;
}

All this can be seen in action, when we are entering “Last Christmas” by “Wham”!

image

The sample code can be downloaded here: SLDataErrorInfo.zip (308.96 KB)

  Posted on: Friday, December 18, 2009 12:06:56 PM (Romance Standard Time, UTC+01:00)   |   Comments [0]
         
Comments are closed.
9/2/2010   9:33:43 PM