Introduction
I do not want to waste time to speak up my things, how I faced hard times when this concept was given to me to apply in my project.
Now I am really satisfied with myself because it induced me to write up this topic. This tip would be more useful to a novice in WPF.
Basically, we can achieve data validation in two ways:
Now, I would like to give you the idea in Part 1 sample project implementation. We will see Part 2 implementation in the upcoming post.
Part 1 - Using the Code
Step 1
Create a project (WpfValidation.csproj), and then create a class file named as “Customer.cs”.
Step 2
In Customer.cs file, create the “Name
” property as given below. If you want to use some logic in name
validation, then use one private
name backing field along with public
property. Here, I do not want to have any additional logic for Name
property. So I simply use Public
property only.
public string Name
{
get; set;
}
Step 3
Implement “IDataErrorInfo
” interface in Customer.cs file.
Import this namespace “using System.ComponentModel
”.
This interface gives us two properties, those are Error
and this
.
Change those two interfaces as below:
public string Error
{
get { return null; }
}
public string this[string columnName]
{
get
{
string result = string.Empty;
if (columnName == "Name")
{
if (this.Name == "")
result = "Name can not be empty";
}
return result;
}
}
Define / assign your message which you want to display when data goes wrong. Here, I used result
variable to store the error message.
Finally our Customer
class looks like:
public class Customer : IDataErrorInfo
{
public string Name
{
get;
set;
}
public string Error
{
get { return null; }
}
public string this[string columnName]
{
get
{
string result = string.Empty;
if (columnName == "Name")
{
if (this.Name == "")
result = "Name can not be empty";
}
return result;
}
}
}
That’s all in the code behind. Now we can move into the XAML part.
Now open “MainWindow.xaml”. Just create two textbox
es with the necessary settings.
- I created two text boxes inside the grid like below:
<TextBox HorizontalAlignment="Left" x:Name="SampleTextBox" Height="35" Width="150" />
<TextBox HorizontalAlignment="Right" x:Name="eTextBox" Height="35" Width="150" Text="Super" />
- Create style in
Resources
section for easy readability. Else, you can have the style
property definition inside <Textbox.Style></Textbox.Style>
. I always prefer the first way, i.e., inside resources
section to reuse the style wherever we want.
<Style x:Key="TextErrorStyle" TargetType="{x:Type TextBox}"> </Style>
Explanation
- Suppose we do have an error in text box, then what are all the things we want to notify to the user that something has gone wrong. (Basically tooltip, and changing background color of textbox).
This style will apply only if “Validation.HasError
” returns true
. So we should specify it in Trigger
property.
<Style x:Key="TextErrorStyle" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="Background" Value="Red"/>
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}"></Setter>
</Trigger>
</Style.Triggers>
</Style>
Here, we should understand about relative source which will get the values from TextBox
control (here SampleTextBox
) by specifying RelativeSource.Self
(which control uses this style, i.e., TextErrorStyle
, we will get all values of that control then which property we’re specifying in Path
property that will be assigned to ToolTip.
- If suppose I want to draw a red color over the text box rather than changing background color. For that, we should define the “
Validation.ErrorTemplate
” property as below:
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate x:Name="TextErrorTemplate">
<DockPanel>
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder/>
</Border>
<TextBlock FontSize="20" Foreground="Red">*?*</TextBlock>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
Tip
<AdornedElementPlaceholder/>
- It is our control here “SampleTextBox
”, based upon this we should place our exclamation or question mark. Basically, we cannot hold two more controls without container (Here DockPanel
) in <ControlTemplate />
, but if our requirement is showing only one control then we can neglect container.
That’s all about style. Now we can move to attaching defined properties to the “SampleTextBox
” control.
- I bound all the properties to the text box control as below. We need to create an instance for
Customer
class. We can follow either in code behind or XAML itself. I used to create in XAML like below.
Import the solution along with project namespace in XAML.
xmlns:local="clr-namespace:WpfValidation"
<Window.Resources>
<local:Customer x:Key="CustomerInstance" Name="Srini"/>
</Window.Resources>
Here, we can pass the default value for our created Name
property.
<TextBox HorizontalAlignment="Left"
x:Name="SampleTextBox" Height="35" Width="150"
Style="{StaticResource TextErrorStyle}">
<TextBox.Text>
<Binding Path="Name" Source="{StaticResource CustomerInstance}"
UpdateSourceTrigger="PropertyChanged" />
</TextBox.Text>
</TextBox>
Here I used “UpdateSourceTrigger = PropertyChanged
” since I want to get notification whenever any keys are entered/deleted. Still it is not over. Two more things are remaining to achieve our target.
- Then now we have used
IDataErrorInfo
in this project, so we have to use "ValidatesOnDataErrors =”True”
".
- Finally,
ValidationRules
needs to be set. DataErrorValidationRule
, ExceptionValidationRule
, NotifyDataErrorValidationRule
are there. I need to throw an exception if my source
property gets updated.
<TextBox HorizontalAlignment="Left"
x:Name="SampleTextBox" Height="35" Width="150">
<TextBox.Text>
<Binding Path="Name" Source="{StaticResource CustomerInstance}"
ValidatesOnDataErrors="True" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<ExceptionValidationRule></ExceptionValidationRule>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Hope it helps you. Thanks a lot for spending your valuable time to read my article. I welcome your comments and suggestions. If you have any feedback, it will be more helpful to improve myself.
Please find the attached sample project for the reference.
History
Updated this post with Part II as well. You can find the link for the Part II article at the top of this post.