navigation
 Wednesday, September 03, 2008

In a previous post, I explained how to use WPF validation rules and error templates to validate user input and provide meaningful feedback for invalid input in the form of tooltips.  Recently, I needed to use these techniques on a WPF textbox which already had non-error tooltip, and observed an unexpected behavior.  The local tooltip overrides the error tooltip, even when an error occurs.  For example, using the code from my previous blog, the following XAML adds a tooltip to the validated TextBox.

<TextBox Margin="10" Width="100" ToolTip="Enter the number of seconds">
    <TextBox.Text>
        <Binding Path="seconds" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <local:posintValidationRule/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

Unfortunately, now my tooltip which displays the validation error no longer appears, although the rest of the error template still works.

image

This behavior actually makes sense if you consider the WPF property precedence rules concerning styles.  Any property that is set locally on the control will always override any setting in the style.  With the precedence rules in mind, there are a few ways we can correct the TextBox's behavior.  As long as the tooltip values are set at the same precedence level, neither value will override the other.

If multiple TextBoxes will use the same standard tooltip when not in an error state, a derivative style would be a simple fix.

<Style x:Key="tbValidatedNumber" TargetType="{x:Type TextBox}" BasedOn="{StaticResource tbValidated}">
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="false">
            <Setter Property="ToolTip"
                Value="Enter a number"/>
        </Trigger>
    </Style.Triggers>
</Style>

If you would rather keep your tooltip value inside the control locally, or if each tooltip is different, you could accomplish the same thing by putting the derived style inside the TextBox.

<TextBox Margin="10" Width="100">
    <TextBox.Text>
        <Binding Path="seconds" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <local:posintValidationRule/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
    <TextBox.Style>
        <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource tbValidated}">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="false">
                    <Setter Property="TextBox.ToolTip"
                Value="Enter a number"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>                        
</TextBox>

Either option will fix our problem, and let both tooltips work properly.

image  image

An alternative solution is to add an additional element to the error template, and show the error message as the new element's tooltip, as shown below.

<Style x:Key="tbValidated" TargetType="{x:Type TextBox}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <Border Background="{TemplateBinding Background}" 
                        x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" 
                        BorderThickness="{TemplateBinding BorderThickness}"
                    CornerRadius="5">
                    <ScrollViewer x:Name="PART_ContentHost"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="Validation.ErrorTemplate">
        <Setter.Value>
            <ControlTemplate>
                <StackPanel Orientation="Horizontal">
                <Border BorderBrush="Yellow" BorderThickness="1" CornerRadius="5">
                    <AdornedElementPlaceholder x:Name="adorner"></AdornedElementPlaceholder>
                </Border>
                <TextBlock Margin="2,0,0,0" Foreground="Yellow" 
                           ToolTip="{Binding ElementName=adorner, 
                    Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">*</TextBlock>
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Now the error message is shown as the tooltip of the star element displayed to the right of the TextBox when a validation fails.  Using the above style, tooltip text can be set locally without affecting the error template behavior.

image  image

There are probably even more ways to achieve similar results, but I have found that one of the three listed here usually meets my needs and allows me to display validation messages easily without sacrificing descriptive tooltips on my controls.

Friday, September 05, 2008 4:15:48 AM UTC
Hi,
Nice work done.but im getting the error as local namespace is missing.what else i have to refer? <local:posintValidationRule/>

rgrds
Kanna..
Friday, September 05, 2008 9:11:00 PM UTC
Hi Kanna,
I think what you're missing is in my previous blog on validation rules located here You need the C# class that creates the validation rule somewhere in your local namespace, and mine is called posintValidationRule, which is what it's looking for and not finding. Hope that helps, and thanks for the comment!
Rachel
Sunday, September 28, 2008 9:07:59 PM UTC
Hi

is there a way to set the Xaml part
<Binding UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:posintValidationRule/>
</Binding.ValidationRules>
</Binding>
in a style for all textboxes, and define only <Binding Path="seconds" ... for single control?
Could you give an example for this ?

Regards
Klaus
Klaus
Tuesday, September 30, 2008 1:18:01 AM UTC
Hello Klaus,
Since the validation rule is part of the binding, there is not a way to set it outside of the binding markup, so for each binding path you will need to specify the validation rule explicitly. If this capability is an integral part of your project, you may need to use a more complex validation method. I found the following post which may be useful to you here on this site. Pay particular attention to the author's answer to the comments, I think it directly applies to your question. Good luck, and thanks for posting!
Rachel
Tuesday, December 23, 2008 1:41:03 AM UTC
I thing, I had the same problem. I solved it by setting up a style for all my TextBox-objects.


<ControlTemplate.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter
TargetName="Bd"
Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=(Validation.Errors)[0].Exception.InnerException.Message}"/>
</Trigger>
</ControlTemplate.Triggers>

With this code it is also possible to display the error message of a property.
Eckhard Großmann
Name
E-mail
Home page

Comment (Some html is allowed: a@href@title, i, strike, u) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Enter the code shown (prevents robots):

Live Comment Preview