XAML GridRow doesn't scale automatically when ErrorTemplate is displayed

61 Views Asked by At

I have a XAML window with a TextBox, and this TextBox has an ErrorTemplate.

The ErrorTemplate is shown below, and as you can see, I have an AdornedElementPlaceholder, followed by a textbox whose Text field is bound to the ErrorContent:

<ControlTemplate x:Key="ValidationErrorTemplateTextBlock" TargetType="{x:Type Control}">
    <Border BorderBrush="Red" BorderThickness="1">
        <StackPanel Orientation="Vertical">
            <AdornedElementPlaceholder Name="AdornedElementPlaceholder" />
            <TextBlock Text="{Binding ElementName=AdornedElementPlaceholder, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" 
                    FontSize="10"
                    Background="Red"
                    Foreground="White"
                    Padding="2" />
        </StackPanel>
    </Border>
</ControlTemplate>

<TextBox IsEnabled="{Binding SendMessage}"
                    Text="{Binding AutoMessageSubject, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"
                    Style="{StaticResource StyleBase}"
                    Validation.ErrorTemplate="{StaticResource ValidationErrorTemplateTextBlock}"
                    HorizontalAlignment="Stretch"
                    Grid.Row="3"
                    Grid.Column="1"
                    Grid.ColumnSpan="2" />

This works fine, except for one thing: the TextBox is inside a GridRow, with a Height="Auto". The row scales itself based on the textbox, but when the ErrorTemplate appears, with an extra TextBox on the bottom - the GridRow doesn't scale up to contain the new TextBox, and the new TextBox overlaps the elements below it.

How can I solve this?

2

There are 2 best solutions below

2
Deepika Dixit On

You might want to try adding Row/Column Definitions:

<Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
1
mechanic On

Validation.ErrorTemplate: Gets or sets the ControlTemplate used to generate validation error feedback on the adorner layer.

This means that if you use Validation.ErrorTemplate, the validation errors are displayed on the layer above usual content, so the "second" TextBlock is displayed over the grid, not within the grid cell.

I would implement INotifyDataErrorInfo instead of semi-obsolete IDataErrorInfo, use a custom textbox style, and bind the visibility of the second TextBlock to HasErrors property. The example below uses a ToolTip instead of the second TextBlock:

       <Style TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <Setter Property="ToolTip">
                        <Setter.Value>
                            <ToolTip DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget}">
                                <ItemsControl DisplayMemberPath="ErrorContent" ItemsSource="{Binding Path=(Validation.Errors)}" />
                            </ToolTip>
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </Style.Triggers>
        </Style>