Articles‎ > ‎WPF Articles‎ > ‎

[ Article ] WPF data validation for error and display error message as tooltip using IDataErrorInfo and error templates

posted Aug 20, 2012, 1:13 AM by Libish Varghese Jacob   [ updated Nov 8, 2012, 9:19 PM ]

Introduction

In this article, we will see how to do validation in WPF and how to display it in the UI. Specifically we will discuss the IDataErrorInfo (System.ComponentModel) to validate error and when to display errors. We will be using control template to create the error template. Later in this article we will see how to show error using error template and displaying error in tooltip of the error template control.

Background

In this article, we will first create a simple WPF application with a textbox and a button. We will validate the text in the textbox when the button is pressed using mechanism provided by IDataErrorInfo. We will then show an error text in an already defined error template. This error template will be a green border around the textbox and exclamation preceding the textbox. Later in this article we will show a tooltip which will display the error text to the user.


Problem it addresses

Most of our application generally has to resort to displaying some kind of UI cues to tell the user what they have done wrong and how they can fix it. In this article we will discuss how input validation can be handled in windows presentation foundation.

Table of contents

  1. Implementing IDataErrorInfo
  2. How to enable validation in WPF xaml
  3. How to Create Error Template to display validation errors.
  4. Display error text in tooltip.

Using the code

To begin with, let’s create a WPF application. Create new project and select WPF Application from the template. After creating the project, add a textbox and a button to the MainWindow.xaml. Now as the window is ready, we need a ViewModel for this MainWindow.xaml. For this, create a class file in your application and name it as MainWindowViewModel.cs. Now we have to bind this class to the WPF window. For this, go to your MainWindow.xaml.cs file and in the constructor, add this line of code as shown below.

public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainWindowViewModel();
        }

You can actually bind your datacontext from xaml as well. But for time being we follow this way. Now got to your MainWindowViewModel.cs and create a string property to bind it to the textbox in your main window as shown below.
public string TextBoxString
   {   
        get;
        set;
   }

Now let’s bind this property to the textbox. To do this, add the below code to your textbox control in you MainWindow.xaml file.

<TextBox Name="textBox1" Text="{Binding TextBoxString, Mode=TwoWay}"/>

Now we need to bind a command to the button. For this let’s create an ICommand property in MainWindowViewModel.cs and bind it to the button.

public ICommand ButtonCommand
        {
            get { return new RelayCommand(); }
         set { }
        }

RelayCommand is a class which we will create which is derived from ICommand interface. We will make this class as simple as possible for this article. As we are not interested in button click action, we are leaving the Execute method empty. If you need to have anything to do with button click, then it is here you need to add the handler.

class RelayCommand : ICommand
    {
        public void Execute(object parameter)
        {            
        }
        public bool CanExecute(object parameter)
        {
            return true;
        }
        public event EventHandler CanExecuteChanged;
    }


If you are using PRISM in your application, then you can actually use DelegateCommand class which is in namespace, Microsoft.Practices.Prism  straightaway without creating this custom class for handling commands. If you are using prism the considering creating ButtonCommand property as shown above like this as shown below.

public ICommand ButtonCommand
        {
            get
            {
                return new DelegateCommand(() =>
                                               {
                                                   string tb = TextBoxString;
                                               });
            }
            set { }
        }

Now let’s bind this property to the button. For this add code as below to your main window xaml file.

<Button Content="Button" Name="button1" Command="{Binding ButtonCommand}"/>


1. Implementing IDataErrorInfo

Now let’s see how to do the validation. For this we need to have our MainWindowViewModel class to inherit form IDataErrorInfo. IDataErrorInfo interface has two members, One is an indexer which and other is a string property as shown below.

public interface IDataErrorInfo
    {
        string this[string columnName] { get; }
        string Error { get; }
    }

We will get control in this indexer when the validation trigger has been raised from UI. Here the column name is the name of the property which is bind to the element which is currently being validated. We can then have our custom code on this property which will validate the value in this property and if found any error then we can return Error message. If everything is clean then return an empty string. Let’s see its implementation in our MainWindowViewModel class. It is as shown below.

public class MainWindowViewModel : IDataErrorInfo
    {
        public string TextBoxString
        {
            get;
            set;
        }

        public ICommand ButtonCommand
        {
            get { return new RelayCommand(); }
            set { }
        }

        public string this[string columnName]
        {
            get
            {
                if ("TextBoxString" == columnName)
                {
                    if (TextBoxString == "test")/*Here if user enters the value as test, then we are displaying an error*/
                    {
                        return Error;
                    }
                }
                return "";
            }
        }

        public string Error
        {
            get { return "test error"; }
        }
    }
  

2. How to enable validation in WPF xaml

Now let’s see how to enable validation. To enable validation, you need to add ValidatesOnDataErrors=True in your binding as shown below. After you have added this, validation is enabled and you should be able to get control in your indexer which we just added in our MainWindowViewModel class. Here the validation will happen only after the button is clicked. Later in this article we will see how to enable the validation in another situation say as user types into the textbox.

<TextBox Name="textBox1" Text="{Binding TextBoxString, Mode=TwoWay, ValidatesOnDataErrors=True}"/>

If you run the application now, you can see a red border around the textbox when error text which in our case is "test" has been entered to the textbox and the button is pressed. This is because by default, WPF will use its default error template to intimate user about the error. The default error template for textbox will be a red border around the textbox to show that there is some error. We can have our custom error template to have it override the default error template and have WPF display errors the way we like to. Let’s see how to create a custom error template and have it bind to the textbox.

3. How to Create Error Template to display validation errors

We will create our Error Template as a static resource and we will design a common template which can be used across similar control across all similar control templates. Here our error template will behave like a green border around our textbox and three red exclamation preceding the text box as shown in the image below.

Error Template Using IDataErrorInfo

The error template is as shown below. Here Key="TextBoxErrorTemplate" is the name of the error template, by referring to this name from the control in WPF, we can add this template to the control.

<Window.Resources>

        <ControlTemplate x:Key="TextBoxErrorTemplate">

            <DockPanel LastChildFill="True">

                <TextBlock DockPanel.Dock="Right" Foreground="Red" FontSize="12pt" >!!!</TextBlock>

                <Border BorderBrush="Green" BorderThickness="1">

                    <AdornedElementPlaceholder />

                </Border>

            </DockPanel>

        </ControlTemplate>

    </Window.Resources>

Here AdornedElementPlaceholder Represents the element used in a ControlTemplate to specify where a decorated control is placed relative to other elements in the ControlTemplate. Now let’s see how this error template is bind to the textbox. For this, refer the static error template as the ErrorTemplate of the textbox as shown below.

<TextBox Name="textBox1" Text="{Binding TextBoxString, Mode=TwoWay, ValidatesOnDataErrors=True}" Validation.ErrorTemplate="{StaticResource TextBoxErrorTemplate}"/>

Now if you can run the application with error condition, then you can see the error template in action.

4. Display error text in tooltip.

Let's just display the error message in a ToolTip. Displaying error message in tooltip in error template is a little tricky. For displaying error message in a tooltip we need a workaround on our error template we were using in last section. To achieve this, we have to create a Style in our Window.Resources section that applies to the Textboxes on this form. When the Validation.HasError changes to true, style sets up a Trigger that sets the ToolTip property to the validation message.

<Window.Resources>
    <Style TargetType="TextBox">
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="true">
                <Setter Property="ToolTip"
                        Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                        Path=(Validation.Errors)[0].ErrorContent}"/>
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>

Now when we run this again, you'll see that when you hover over the TextBox the validation message is displayed in a ToolTip. But this solution only displays for TextBoxes. What about the rest the controls like Label, CheckBoxes, and Dropdown etc…? To achieve this, we can do something as given below.


<Window.Resources>
        <Style TargetType="Control" x:Key="myErrorTemplate">
            <Setter Property="Validation.ErrorTemplate">
                <Setter.Value>
                    <ControlTemplate>
                        <DockPanel LastChildFill="True">
                            <TextBlock DockPanel.Dock="Right" Foreground="Red" FontSize="12pt" >!!!</TextBlock>
                            <Border BorderBrush="Green" BorderThickness="1" >
                                <AdornedElementPlaceholder Name="myControl"/>
                            </Border>
                        </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}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
        <Style TargetType="TextBox" BasedOn="{StaticResource myErrorTemplate}" />
<!--<Style TargetType="CheckBox" BasedOn="{StaticResource myErrorTemplate}" />-->

</Window.Resources>


Here as the style is taking care of the error display, we don’t have to specify the Validation Error Template as Validation.ErrorTemplate in our applications textbox. We can remove that.

<TextBox Name="textBox1" Text="{Binding TextBoxString, Mode=TwoWay, ValidatesOnDataErrors=True}" Validation.ErrorTemplate="{StaticResource TextBoxErrorTemplate}"/>

We can also specify that the TargetType="Control" and then we can declare additional styles for the rest of our controls. Here we are adding the style to window resource, as the style is in the window resource, style will be applicable only to controls in that particular window. If you want to have it across all your windows in your application, try adding this style in your resources section (Application.resources) inside your App.xaml.

Points of Interest

Happy coding :)

History

This is the first version of the article [Article WPF data validation for error and display error message using IDataErrorInfo and error templates]. Any update to this article will be listed here.

Comments