WPF provides an easy-to-implement way to validate entered data and notify the user when something is incorrect. An example is available in MSDN, so I will skip further explanation how does this work…

Everything works like a charm till you validate data bound to the main object. For instance let’s examine code below:
public abstract class AbstractCity : ICity
{
private string name;
private Country country;
public string Name
{
get { return name; }
set
{
if (name != value)
{
name = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
public virtual Country Country
{
get
{
return country;
}
set
{
if (country != value)
{
country = value;
ExecutePropertyChanged("Country");
}
}
}
public string this[string columnName]
{
get
{
switch (columnName)
{
case "Name":
return String.IsNullOrWhiteSpace(Name) ? "City name must be set" : String.Empty;
case "Country":
return Country == null ? "Country must be set" : String.Empty;
default:
return String.Empty;
}
}
}
public string Error
{
get { return this["Name"]; }
}
protected void ExecutePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class CityNullCountry : AbstractCity { }
and binding in XAML:
<TextBox Grid.Column="1" Grid.Row="0" Text="{Binding Path=City.Name, ValidatesOnDataErrors=True, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Grid.Column="1" Grid.Row="1" HorizontalAlignment="Left" Width="250" Text="{Binding Path=City.Country.Code, Mode=OneWay, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" IsReadOnly="True"/>
<ComboBox Grid.Column="1" Grid.Row="1" HorizontalAlignment="Right" Width="100" SelectedItem="{Binding Path=City.Country}" ItemsSource="{Binding Path=Countries}" DisplayMemberPath="Code"/>
<TextBox Grid.Column="1" Grid.Row="2" Text="{Binding Path=City.Country.Name, ValidatesOnDataErrors=True, NotifyOnValidationError=True, Mode=OneWay}" IsReadOnly="True"/>
In this code it is very easy to validate and notify the user when Name property in CityNullCountry object is NULL or empty. But there is no easy solution to validate City.Country.Name property. The reason is that the Country object may not exist when City object is created.
So as of now we know that WPF needs Country class instance in order to validate it (using IDataErrorInfo in that class) and notify user when something is wrong. Some of you may ask, why I don’t check the Country object in the City class. The answer is simple. WPF validates bounded object and in that case it is the Country object and its Name property. Text=“{Binding Path=City.Country.Name, ValidatesOnDataErrors=True, NotifyOnValidationError=True, Mode=OneWay}“. TextBox with such binding will check for IDataErrorInfo interface in Country class… but Country object may be empty and nothing will be validated. The user will not be aware of any errors at all.
So, my solution is fairly easy. I will simply provide a fake Country object when the real object is NULL. Validation will run against my fake object and errors will popup in the user interface. One way to achieve that is to use Activator.CreateInstance() method. The whole mechanism implementation is showed below:
public class CityNullIsDefaultCountry : AbstractCity
{
private Country country;
protected DefaultsTable defaults = new DefaultsTable();
public override Country Country
{
get
{
return defaults.GetObjectOrDefault(country, "Country");
}
set
{
if (country != value)
{
country = value;
ExecutePropertyChanged("Country");
}
}
}
}
public class DefaultsTable
{
readonly Dictionary<string, object> defaults = new Dictionary<string, object>();
public T GetObjectOrDefault<T>(T obj, string propName) where T : class
{
if (obj != null)
return obj;
if (defaults.ContainsKey(propName))
return (T)defaults[propName];
T defaultObject = (T)Activator.CreateInstance(typeof(T));
defaults.Add(propName, defaultObject);
return defaultObject;
}
}
DefaultsTable defaults = new DefaultsTable(); is responsible for providing fake object if it is NULL. When we set the Country property to some value, this value will be returned.
One of the challenges now is to determine what kind of object is returned when we access Country property on City class… I will discuss that somewhere in the future. In short: this can be determined by adding IsDefault flag and checking it.
Sample code for this example can be found here