Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

WPF Validation - Using IDataErrorInfo

0.00/5 (No votes)
31 Dec 2014 1  
Focus on WPF Novice to easily understand Data Validation using IDataErrorInfo interface

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 textboxes with the necessary settings.

  1. 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" />
  2. 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
    1. 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.

    2. 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.

  3. 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.

  4. Then now we have used IDataErrorInfo in this project, so we have to use "ValidatesOnDataErrors =”True”".
  5. 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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here