How to extend a control in WPF to make room for error messages in ErrorTemplate?

I have a WPF window that uses validation. I created an error template that places a red frame around an element that does not perform validation and displays an error message below. This works fine, but an error message is displayed on top of any controls below the error control. The best I can say is because the error template is displayed at the Adorner Layer level, which is on top of everything else. I would like everything to happen to move down to make room for the error message. Is there any way to do this? All the examples on the Internet seem to use the tooltip and use a simple indicator, such as an asterisk or exclamation point, which does not use a lot of space.

Here is the template:

<ControlTemplate x:Key="ValidationErrorTemplate">
    <StackPanel>
        <Border BorderBrush="Red" BorderThickness="2" CornerRadius="2">
            <AdornedElementPlaceholder x:Name="placeholder"/>
        </Border>
        <TextBlock Foreground="Red" FontSize="10" Text="{Binding ElementName=placeholder, Path=AdornedElement.(Validation.Errors)[0].ErrorContent, FallbackValue=Error!}"></TextBlock>
    </StackPanel>
</ControlTemplate>

( , ):

<Grid>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="Auto"/>
  </Grid.RowDefinitions>
  <TextBox Name="Account" Grid.Row="0" Validation.ErrorTemplate="{StaticResource ValidationErrorTemplate}" Width="200">
    <TextBox.Text>
      <Binding Path="AccountNumber">
        <Binding.ValidationRules>
          <validators:RequiredValueValidationRule/>
          <validators:NumericValidationRule/>
        </Binding.ValidationRules>
      </Binding>
    </TextBox.Text>
  </TextBox>
  <TextBox Name="Expiration" Grid.Row="1" Validation.ErrorTemplate="{StaticResource ValidationErrorTemplate}" Width="100"  Margin="0,2,5,2">
    <TextBox.Text>
      <Binding Path="ExpirationDate">
        <Binding.ValidationRules>
          <validators:ExpirationDateValidationRule/>
        </Binding.ValidationRules>
      </Binding>
    </TextBox.Text>
  </TextBox>
</Grid>
+3
1

EDIT: , , ( , - ), :

Validation.ErrorTeplate, AdornerLayer, Validation.HasError (Validation.Errors) [0].ErrorContent, IValueConverter Validation.HasError bool . :

Window1.cs:

<Window x:Class="WpfApplicationTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    xmlns:local="clr-namespace:WpfApplicationTest"
    Title="Window1" Height="300" Width="300">
    <Grid Margin="10">
        <Grid.Resources>
            <!-- The person we are binding to -->
            <local:Person x:Key="charles" Name="Charles" Age="20" />
            <!-- The convert to use-->
            <local:HasErrorToVisibilityConverter x:Key="visibilityConverter" />
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <!-- The name -->
        <TextBox Name="NameTextBox" Grid.Row="0" Text="{Binding Source={StaticResource charles}, Path=Name, ValidatesOnDataErrors=true}" />
        <TextBlock Grid.Row="1" 
                   Foreground="Red" 
                   Text="{Binding ElementName=NameTextBox, Path=(Validation.Errors)[0].ErrorContent}" 
                   Visibility="{Binding ElementName=NameTextBox, Path=(Validation.HasError), Converter={StaticResource visibilityConverter}}" />

        <!-- The age -->
        <TextBox Name="AgeTextBox" Grid.Row="2" Text="{Binding Source={StaticResource charles}, Path=Age, ValidatesOnExceptions=true}" />
        <TextBlock Grid.Row="3" 
                   Foreground="Red" 
                   Text="{Binding ElementName=AgeTextBox, Path=(Validation.Errors)[0].ErrorContent}" 
                   Visibility="{Binding ElementName=AgeTextBox, Path=(Validation.HasError), Converter={StaticResource visibilityConverter}}" />
    </Grid>
</Window>

Person.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Text.RegularExpressions;

namespace WpfApplicationTest
{
    public class Person : IDataErrorInfo
    {
        public string Name { get; set; }
        public int Age { get; set; }

        #region IDataErrorInfo Members

        string IDataErrorInfo.Error
        {
            get { throw new NotImplementedException(); }
        }

        string IDataErrorInfo.this[string columnName]
        {
            get
            {
                switch (columnName)
                {
                    case ("Name"):
                        if (Regex.IsMatch(this.Name, "[^a-zA-Z ]"))
                        {
                            return "Name may contain only letters and spaces.";
                        }
                        else
                        {
                            return null;
                        }
                    default:
                        return null;
                }
            }
        }

        #endregion
    }
}

HasErrorToVisibilityConverter.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Windows;

namespace WpfApplicationTest
{
    [ValueConversion(typeof(bool), typeof(Visibility))]
    public class HasErrorToVisibilityConverter : IValueConverter
    {
        #region IValueConverter Members

        object IValueConverter.Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool hasError = (bool)value;
            return hasError ? Visibility.Visible : Visibility.Collapsed;
        }

        object IValueConverter.ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}

, ControlTemplate, , , . - , WPF, "!". '*', , , (Validation.Errors) [0].ErrorContent...

! , ;)

+5

Source: https://habr.com/ru/post/1702154/


All Articles