/*
Place the IDataErrorInfo implementation in your Model Class ..
not your view model.
The data error is in the Model not in the ViewModel.
The ViewModel references the model,
IDataErrorInfo communicates with the binding via the
xaml ValidatesOnDataErrors=True in the binding
*/
/* model */
public class OldBoy : Screen, IOldBoy, IDataErrorInfo
{
private Guid oldBoyId;
public Guid OldBoyId
{
get
{
return this.oldBoyId;
}
set
{
this.oldBoyId = value;
NotifyOfPropertyChange(() => OldBoyId);
}
}
private string firstName;
public string Firstname
{
get
{
return this.firstName;
}
set
{
this.firstName = value;
NotifyOfPropertyChange(() => Firstname);
}
}
private string surName;
public string Surname
{
get
{
return this.surName;
}
set
{
this.surName = value;
NotifyOfPropertyChange(() => Surname);
}
}
/* include a Property e.g. CanSave in your Model that will be bound
to the IsEnabled DependencyProperty ofIsEnabled on your Submit Button
Viz.
*/
public string this[string name]
{
get
{
string result = null;
if (name == "Firstname")
{
// force the issue
this.CanSave = true;
if (string.IsNullOrEmpty(this.Firstname))
{
result = "Model says that Firstname must be entered";
}
}
if (name == "Surname")
{
// force the issue
this.CanSave = true;
if (string.IsNullOrEmpty(this.Surname))
{
result = "Model says that Surname must be entered";
}
}
return result;
}
}
public string Error
{
get
{
return null;
}
}
private bool canSave;
public bool CanSave
{
get
{
return this.canSave;
}
set
{
if (string.IsNullOrEmpty(this.Firstname) || string.IsNullOrEmpty(this.surName))
{
this.canSave = false;
}
else
{
this.canSave = true;
}
NotifyOfPropertyChange(() => CanSave);
}
}
}
/* in the ViewModel the underlying class for the edit window */
public class DetailsViewModel : Screen, IDetailsViewModel
{
private IOldBoy editingOldBoyItem;
public IOldBoy EditingOldBoyItem
{
get
{
return this.editingOldBoyItem;
}
set
{
this.editingOldBoyItem = value;
NotifyOfPropertyChange(() => EditingOldBoyItem);
}
}
// elided
}
xaml textboxes involved in validation
<Label Grid.Row="00"
Grid.Column="00"
Content="First Name" />
<TextBox Text="{Binding Path=EditingOldBoyItem.Firstname, ValidatesOnDataErrors=True, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource TextBoxCellValidationStyle}"
Grid.Row="00"
Grid.Column="01">
<i:Interaction.Behaviors>
<local:BindableFocusBehavior HasFocus="{Binding SetFocusToFirstName, Mode=TwoWay, UpdateSourceTrigger=Default}" />
</i:Interaction.Behaviors>
</TextBox>
<Label Grid.Row="01"
Grid.Column="00"
Content="Surname" />
<TextBox Text="{Binding Path=EditingOldBoyItem.Surname, ValidatesOnDataErrors=True, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Validation.ErrorTemplate="{StaticResource ValidationTemplate}"
Grid.Row="01"
Grid.Column="01">
<!-- save button that is disabled when CanSave is false -->
<Button Content="Save Edit"
IsEnabled="{Binding Path=EditingOldBoyItem.CanSave}"
x:Name="Save"
Margin="4"
Template="{StaticResource RedGlassButton}" />
app.xaml
<ControlTemplate x:Key="ValidationTemplate">
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Bottom"
FontSize="12"
FontWeight="Bold"
Foreground="Red">
<TextBlock.ToolTip>
<ToolTip Placement="Center"
Style="{StaticResource ErrorToolTip}">
<TextBlock Foreground="White">
<TextBlock.Text>
<Binding Path="/ErrorContent" />
</TextBlock.Text>
</TextBlock>
</ToolTip>
</TextBlock.ToolTip>
</TextBlock>
<Border BorderBrush="Red"
BorderThickness="1">
<AdornedElementPlaceholder Name="adornerPlaceholder" />
</Border>
</DockPanel>
</ControlTemplate>
<Style x:Key="TextBoxCellValidationStyle"
BasedOn="{StaticResource {x:Type TextBox}}"
TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="Background" Value="LightCyan" />
<Setter Property="Foreground" Value="Red" />
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ValidationTemplate}" />
</Trigger>
</Style.Triggers>
</Style>