Introduction
Part I: implements IDataErrorInfo interface
I really want to say thanks to readers who read my previous post “WPF Validation – using DataErrorInfo
” for their comments and wishes.
Now I got time to write another post in Part - II “WPF Validation – using INotifyDataErrorInfo
”.
Using the Code
It is always better to have some theoretical knowledge before implementing the same.
Let’s dive into that.
Implementation of INotifyDataErrorInfo
interface returns 3 things:
HasErrors
– bool
property GetErrors
– IEnumerable
type ErrorsChanged
– Event
Two things are the main difference compared to IDataErrorInfo
interface implementation.
- Checks the validation asynchronously
- The ability to store and retrieve multiple errors for single property
We will see this in a very detailed way in the below part of this post.
First, we can see the coding side, then go for XAML styling later.
Step 1
Implement INotifyDataErrorInfo
interface in Customer
class.
public class Customer : INotifyDataErrorInfo
{
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public System.Collections.IEnumerable GetErrors(string propertyName)
{ }
public bool HasErrors
{
get
{
return true;
}
}
}
Step 2
Define Dictionary<string, List<string>>
locally.
Dictionary<string, List<string>> propErrors = new Dictionary<string, List<string>>();
Here is one for property name, another one for list of errors for the given property.
Step 3
We should check the HasErrors
property, whether it returns true
or not. If it returns true
, then only data validation will be highlighted. Data validation will not be notified to the user when errors content is there but this property returns false
. So make sure that this property returns true
based on error values count
from propErrors
.
public bool HasErrors
{
get
{
try
{
var propErrorsCount = propErrors.Values.FirstOrDefault(r =>r.Count>0);
if (propErrorsCount != null)
return true;
else
return false;
}
catch { }
return true;
}
}
Step 4
We should get the list of defined errors from the Dictionary
.
public System.Collections.IEnumerable GetErrors(string propertyName)
{
List<string> errors = new List<string>();
if (propertyName != null)
{
propErrors.TryGetValue (propertyName, out errors);
return errors;
}
else
return null;
}
Step 5
In the OnPropertyChanged()
method, we call Validate()
to get the errors for each property we have in the Customer
class.
Some cases, we will have more validation string
s for one property. Those defined validation string
s will be added into List<string> listErrors;
this list is assigned to dictionary
.
propErrors ["Name"] = listErrors;
If listErrors. Count > 0
, then raise the ErrorsChanged
Event.
That's all coding. Now we can go for styling in XAML.
XAML part - Styling part remains the same as what we have done for IDataErrorInfo
implementation. Only one thing is replace ValidatesOnDataErrors
with ValidatesOnNotifyDataErrors
property to true
.
<Style x:Key="TextErrorStyle" TargetType="{x:Type TextBox}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate x:Name="TextErrorTemplate">
<DockPanel LastChildFill="True">
<AdornedElementPlaceholder>
<Border BorderBrush="Red"
BorderThickness="2"/>
</AdornedElementPlaceholder>
<TextBlock FontSize="20"
Foreground="Red">*?*</TextBlock>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError"
Value="True">
<Setter Property="ToolTip"
Value="{Binding RelativeSource=
{x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}"></Setter>
</Trigger>
</Style.Triggers>
</Style>
Then bind this style to the text box control which we want to validate.
<TextBox HorizontalAlignment="Left" Margin="10"
x:Name="SampleTextBox" Height="35" Width="150"
Style="{StaticResource TextErrorStyle}"
Text="{Binding Source={StaticResource CustomerInstance},Path=Name,Mode=TwoWay,
ValidatesOnNotifyDataErrors=True,UpdateSourceTrigger=PropertyChanged}">
</TextBox>
Here Source
is nothing but the Customer
class instance:
xmlns:local="clr-namespace:WpfValidation"
<Window.Resources>
<local:Customer x:Key="CustomerInstance" Name="Welcome"/>
</Window.Resources>
That’s all guys. :)
I've attached the code sample for your easy reference. Anyway, if you want to give it a try, then just get my previous post code sample, from there you can just try to implement this concept.
Hope you all got this concept well. I welcome your comments, questions and suggestions if any.
Points of Interest
I learnt how to use and when to use TPL while implementing this concept for sample application since INotifyDataErrorInfo
can be done asynchronously.
History
XAML part styling has been added.
Simple Concept for achieving anything "Practice... Practice... Practice..." will make you stronger irrespective of the background of person!!!".