Next to the full support of the data binding engine for the IDataErrorInfo interface, Silverlight 4 adds a new interface called INotifyDataErrorInfo, offering more options for particular scenario's. In this post, we’ll look at a small example using this interface.
IDataErrorInfo allows retrieving the error on a per-property basis. It’s not possible however to validate all properties of the entity in one go. This becomes possible with the INotifyDataErrorInfo. Let’s look at the interface first.
public interface INotifyDataErrorInfo
{
bool HasErrors { get; }
event EventHandler ErrorsChanged;
IEnumerable GetErrors( string propertyName);
}
This interface has some nice advantages. As said, we can check if the entity as a whole is in an invalid state through the HasErrors property. Retrieving the errors using the GetErrors can now retrieve other things than just strings which was all that we could do with the IDataErrorInfo. On top of that, a property can have more than just one validation error at the same time
The ErrorsChanged event can come in handy if there’s a long running process needed to perform validation: assume that for some validation, we need to go to the database over a service. The ErrorsChanged event allows us to notify the UI if the validation errors change. If ValidatesOnNotifyDataErrors is set to true on the UI, Silverlight will listen for the ErrorsChanged event and will display any errors if they are added afterwards.
That’s it for this interface, let’s now look at it in an example. I have changed the example created for the IDataErrorInfo to work with INotifyDataErrorInfo, so the interface has remained the same.
The errors I want to return to my interface are more than just strings. I created a custom error as follows:
public class ChristmasSongError
public ErrorLevel Severity{ get; set; }
public string ErrorName { get; set; }
public string ErrorMessage { get; set; }
public override string ToString()
return ErrorName + ": " + ErrorMessage;
The ChristmasSong class now implements the INotifyDataErrorInfo interface. Let’s focus on the Title property. When its value is set, it calls a validation method. In this method, I create an instance of the custom error, specifying all the property values. If there’s an error, here the title being empty, I add it to a Dictionary called errors using the AddError method. If validation is satisfied, it’s removed using the RemoveError method. The errrors Dictionary is used so it is possible for each property to have more than one error: each property has as its value a List.
public class ChristmasSong : INotifyDataErrorInfo
private string title;
private string performedBy;
private TimeSpan duration;
private DateTime published;
private string error;
public Dictionary<string, List> errors =
new Dictionary<string,List>();
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;
ValidateTitleProperty();
private void ValidateTitleProperty()
ChristmasSongError christmasSongError = new ChristmasSongError()
{ Severity = ErrorLevel.Error, ErrorName = "TitleRequired",
ErrorMessage = "Title should not be empty" };
if (string.IsNullOrEmpty(title))
AddError( "Title", christmasSongError);
else
RemoveError( "Title", "TitleRequired");
public string PerformedBy
return performedBy;
performedBy = value;
ValidatePerformedByProperty();
private void ValidatePerformedByProperty()
{ Severity = ErrorLevel.Error, ErrorName = "PerformedByRequired",
ErrorMessage = "The artist should not be empty" };
if (string.IsNullOrEmpty(performedBy))
AddError( "PerformedBy", christmasSongError);
RemoveError( "PerformedBy", "PerformedByRequired");
public TimeSpan Duration
return duration;
duration = value;
ValidateDuration();
private void ValidateDuration()
ChristmasSongError durationNullError = new ChristmasSongError()
{ Severity = ErrorLevel.CriticalError, ErrorName = "DurationNull",
ErrorMessage = "The duration should not be empty" };
ChristmasSongError durationTooLongError = new ChristmasSongError()
{ Severity = ErrorLevel.Error, ErrorName = "DurationTooLong",
ErrorMessage = "The duration is too long" };
if (duration == TimeSpan.Zero)
AddError( "Duration", durationNullError);
RemoveError( "Duration", "DurationNull");
if (duration.TotalSeconds > 500)
AddError( "Duration", durationTooLongError);
RemoveError( "Duration", "DurationTooLong");
public DateTime Published
return published;
published = value;
VaidatePublished();
private void VaidatePublished()
ChristmasSongError publishedTooLow = new ChristmasSongError()
{ Severity = ErrorLevel.CriticalError, ErrorName = "PublishedTooLow",
ErrorMessage = "The date is too small" };
ChristmasSongError publishedTooHigh = new ChristmasSongError()
{ Severity = ErrorLevel.CriticalError, ErrorName = "PublishedTooHigh",
ErrorMessage = "The date is too high" };
if (published < new DateTime(1900, 1, 1))
AddError( "Published", publishedTooLow);
RemoveError( "Published", "PublishedTooLow");
if (published > new DateTime( 2010, 1, 1))
AddError( "Published", publishedTooHigh);
RemoveError( "Published", "PublishedTooHigh");
private void AddError(string propertyName, ChristmasSongError error)
if (!errors.ContainsKey(propertyName))
errors.Add(propertyName, new List() { error });
else// adding the error to the already existing list
var list = errors[propertyName];
list.Add(error);
if (ErrorsChanged != null)
ErrorsChanged( this, new DataErrorsChangedEventArgs(propertyName));
private void RemoveError(string propertyName, string errorName)
if (errors.ContainsKey(propertyName))
var christmasSongError = errors[propertyName]
.Where (e => e.ErrorName == errorName).FirstOrDefault();
list.Remove(christmasSongError);
if (list.Count == 0)//no more errors for this property
errors.Remove(propertyName);
public event EventHandler ErrorsChanged;
public System.Collections.IEnumerable GetErrors(string propertyName)
if (string.IsNullOrEmpty(propertyName))//retrieve errors for entire entity
return errors.Values;
return errors[propertyName];
return null;
public bool HasErrors
if (errors.Count == 0)
return false;
return true;
With the entity in place, we can look at the UI. The XAML code is similar to the IDataErrorInfo example, although we should now use the ValidatesOnNotifyDataErrors and set it to True. Below is part of the code, for the entire listing, see the download.
<
The complete sample can be downloaded here: SLINotifyDataErrorInfo.zip (602.56 KB)
Ads by The Lounge
All content is property of www.snowball.be. Nothing on this site can be copied or published elsewhere, unless otherwise stated.
This site is made by Gill Cleeren.
Questions? Opinions? E-mail