Kazimierz Matyaszek
Kazimierz Matyaszek
3 min read

Categories

Tags

In this post, I will show how you can present user input validation errors to the user. By default, WPF shows a red border around the TextBox when the entered value is invalid. But in this case, our user has no idea what is wrong with entered data. We need to inform the user by providing an error message on the view.

To show you available option I created a sample project. You can find it under the link: https://github.com/kmatyaszek/WPFValidationDisplayErrors

In our sample project, we have four TextBox elements. Each of them presents a different style of presenting the occurred error to the user. When an error occurs (user entered value equals test) on the data binding the attached property Validation.HasError property is set to true on the target element of the data binding process (in our case it’s TextBox element). So we can use this property to indicate if the value entered by the user is invalid. We also can use Validation.Errors attached property to retrieve error message.

Below you can see the output of our sample project. As you can see when I typed value test to each of the TextBox each of them shows me an error message in the different form.

In this example, I focused on presenting the error message to the user so I decided to use the ValidatesOnExceptions mechanism (to read more about this please go to the following link: WPF Validation - Using ValidatesOnExceptions). Let’s look at the source code especially on XAML code.

<Window x:Class="WPFValidationDisplayErrors.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="400">
    <Window.Resources>
        <Style TargetType="Label">
            <Setter Property="Margin" Value="5" />
            <Setter Property="VerticalAlignment" Value="Center" />
        </Style>
        <Style x:Key="DefaultTextBoxStyle" TargetType="TextBox">
            <Setter Property="Margin" Value="5" />
            <Setter Property="VerticalAlignment" Value="Center" />
        </Style>

        <Style x:Key="ToolTipWithErrorMessageOnErrorStyle" TargetType="TextBox" BasedOn="{StaticResource DefaultTextBoxStyle}">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
                </Trigger>
            </Style.Triggers>
        </Style>

        <Style x:Key="RedBackgroundOnErrorStyle" TargetType="TextBox" BasedOn="{StaticResource ToolTipWithErrorMessageOnErrorStyle}">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <Setter Property="Background" Value="Red" />
                </Trigger>
            </Style.Triggers>
        </Style>

        <Style x:Key="CustomErrorControlOnErrorStyle" TargetType="TextBox" BasedOn="{StaticResource DefaultTextBoxStyle}">
            <Setter Property="Validation.ErrorTemplate">
                <Setter.Value>
                    <ControlTemplate>
                        <StackPanel>
                            <AdornedElementPlaceholder x:Name="placeholder" />
                            <TextBlock FontSize="11" FontStyle="Italic" Foreground="Red"
                                       Text="{Binding ElementName=placeholder, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" />
                        </StackPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid Grid.IsSharedSizeScope="True">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" SharedSizeGroup="Labels" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <Label Content="Default:" />
        <TextBox Grid.Column="1"
                 Text="{Binding Path=Default, Mode=TwoWay, ValidatesOnExceptions=True, UpdateSourceTrigger=PropertyChanged}"
                 Style="{StaticResource DefaultTextBoxStyle}" />

        <Label Content="ToolTip:" Grid.Row="1" />
        <TextBox Grid.Column="1" Grid.Row="1"
                 Text="{Binding Path=ToolTip, Mode=TwoWay, ValidatesOnExceptions=True, UpdateSourceTrigger=PropertyChanged}"
                 Style="{StaticResource ToolTipWithErrorMessageOnErrorStyle}" />

        <Label Content="Background and ToolTip:" Grid.Row="2" />
        <TextBox Grid.Column="1" Grid.Row="2"
                 Text="{Binding Path=Background, Mode=TwoWay, ValidatesOnExceptions=True, UpdateSourceTrigger=PropertyChanged}"
                 Style="{StaticResource RedBackgroundOnErrorStyle}" />

        <Label Content="Custom error template:" Grid.Row="3" />
        <TextBox Grid.Column="1" Grid.Row="3"
                 Text="{Binding Path=CustomError, Mode=TwoWay, ValidatesOnExceptions=True, UpdateSourceTrigger=PropertyChanged}"
                 Style="{StaticResource CustomErrorControlOnErrorStyle}" />
    </Grid>
</Window>

As you can see in the above code snippet we defined TextBox styles in the Window resources section. As I mentioned before to indicate if we should show error message we’re using attached Validation.HasError property. In the first row is presented default behavior of the validation errors in WPF, it only shows a red border around the TextBox. In the second row, I created a custom style to show an error message in the tooltip. In the third row, I added the background color if the value is invalid. And in the last row, I created custom error template to show error message right below TextBox.