Themes/MaterialDesignTheme.ValidationErrorTemplate.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:converters="clr-namespace:MaterialDesignThemes.Wpf.Converters"
                    xmlns:wpf="clr-namespace:MaterialDesignThemes.Wpf">
  <ControlTemplate x:Key="MaterialDesignValidationErrorTemplate">
    <ControlTemplate.Resources>
      <converters:ThicknessCloneConverter x:Key="FloatingHintValidationErrorTextMarginConverter" CloneEdges="Left" />
      <converters:ThicknessCloneConverter x:Key="FilledValidationErrorTextMarginConverter"
                                          CloneEdges="Left"
                                          FixedBottom="2"
                                          FixedTop="2" />
      <converters:ThicknessCloneConverter x:Key="OutlinedValidationErrorTextMarginConverter"
                                          CloneEdges="Left"
                                          FixedTop="2" />
 
      <DataTemplate DataType="{x:Type ValidationError}">
        <TextBlock MaxWidth="{Binding ElementName=Placeholder, Path=ActualWidth}"
                   Margin="2"
                   HorizontalAlignment="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.HorizontalAlignment)}"
                   FontSize="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.FontSize)}"
                   Foreground="{DynamicResource MaterialDesign.Brush.ValidationError}"
                   Text="{Binding ErrorContent, Mode=OneTime}"
                   TextWrapping="Wrap"
                   UseLayoutRounding="false" />
      </DataTemplate>
    </ControlTemplate.Resources>
    <StackPanel>
      <AdornedElementPlaceholder Name="Placeholder" />
      <Border x:Name="DefaultErrorViewer"
              Margin="{Binding ElementName=Placeholder, Path=AdornedElement.Padding, Converter={StaticResource FloatingHintValidationErrorTextMarginConverter}}"
              Background="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.Background)}"
              Visibility="Collapsed">
        <TextBlock MaxWidth="{Binding ElementName=Placeholder, Path=ActualWidth}"
                   Margin="0,2"
                   HorizontalAlignment="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.HorizontalAlignment)}"
                   FontSize="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.FontSize)}"
                   Foreground="{DynamicResource MaterialDesign.Brush.ValidationError}"
                   Text="{Binding /ErrorContent, Mode=OneTime}"
                   TextWrapping="Wrap"
                   UseLayoutRounding="false" />
      </Border>
      <wpf:PopupEx x:Name="ValidationPopup"
                   AllowsTransparency="True"
                   IsOpen="False"
                   Placement="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.PopupPlacement)}"
                   PlacementTarget="{Binding ElementName=Placeholder, Mode=OneWay}">
        <Border x:Name="PopupBorder" Background="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.Background)}">
          <TextBlock Margin="0,2"
                     HorizontalAlignment="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.HorizontalAlignment)}"
                     FontSize="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.FontSize)}"
                     Foreground="{DynamicResource MaterialDesign.Brush.ValidationError}"
                     Text="{Binding /ErrorContent, Mode=OneTime}"
                     TextWrapping="Wrap"
                     UseLayoutRounding="false" />
        </Border>
      </wpf:PopupEx>
    </StackPanel>
    <ControlTemplate.Triggers>
      <MultiDataTrigger>
        <MultiDataTrigger.Conditions>
          <Condition Binding="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.OnlyShowOnFocus)}" Value="False" />
          <Condition Binding="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.UsePopup)}" Value="True" />
          <Condition Binding="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.Suppress)}" Value="False" />
        </MultiDataTrigger.Conditions>
        <MultiDataTrigger.Setters>
          <Setter TargetName="ValidationPopup" Property="IsOpen" Value="True" />
        </MultiDataTrigger.Setters>
      </MultiDataTrigger>
 
      <MultiDataTrigger>
        <MultiDataTrigger.Conditions>
          <Condition Binding="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.OnlyShowOnFocus)}" Value="False" />
          <Condition Binding="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.UsePopup)}" Value="False" />
          <Condition Binding="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.Suppress)}" Value="False" />
        </MultiDataTrigger.Conditions>
        <MultiDataTrigger.Setters>
          <Setter TargetName="DefaultErrorViewer" Property="Visibility" Value="Visible" />
        </MultiDataTrigger.Setters>
      </MultiDataTrigger>
 
      <MultiDataTrigger>
        <MultiDataTrigger.Conditions>
          <Condition Binding="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.OnlyShowOnFocus)}" Value="True" />
          <Condition Binding="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.UsePopup)}" Value="True" />
        </MultiDataTrigger.Conditions>
        <MultiDataTrigger.Setters>
          <Setter TargetName="ValidationPopup" Property="IsOpen" Value="{Binding ElementName=Placeholder, Path=AdornedElement.IsKeyboardFocusWithin, Mode=OneWay}" />
        </MultiDataTrigger.Setters>
      </MultiDataTrigger>
 
      <MultiDataTrigger>
        <MultiDataTrigger.Conditions>
          <Condition Binding="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.OnlyShowOnFocus)}" Value="True" />
          <Condition Binding="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.UsePopup)}" Value="False" />
        </MultiDataTrigger.Conditions>
        <MultiDataTrigger.Setters>
          <Setter TargetName="DefaultErrorViewer" Property="Visibility" Value="{Binding ElementName=Placeholder, Path=AdornedElement.IsKeyboardFocusWithin, Mode=OneWay, Converter={x:Static converters:BooleanToVisibilityConverter.CollapsedInstance}}" />
        </MultiDataTrigger.Setters>
      </MultiDataTrigger>
 
      <DataTrigger Binding="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:ValidationAssist.Background)}" Value="{x:Null}">
        <Setter TargetName="DefaultErrorViewer" Property="Background" Value="{DynamicResource MaterialDesign.Brush.Background}" />
        <Setter TargetName="PopupBorder" Property="Background" Value="{DynamicResource MaterialDesign.Brush.Background}" />
      </DataTrigger>
 
      <DataTrigger Binding="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:TextFieldAssist.HasOutlinedTextField)}" Value="True">
        <Setter TargetName="DefaultErrorViewer" Property="Margin" Value="{Binding ElementName=Placeholder, Path=AdornedElement.Padding, Converter={StaticResource OutlinedValidationErrorTextMarginConverter}}" />
        <Setter TargetName="ValidationPopup" Property="VerticalOffset" Value="2" />
      </DataTrigger>
 
      <DataTrigger Binding="{Binding ElementName=Placeholder, Path=AdornedElement.(wpf:TextFieldAssist.HasFilledTextField)}" Value="True">
        <Setter TargetName="DefaultErrorViewer" Property="Margin" Value="{Binding ElementName=Placeholder, Path=AdornedElement.Padding, Converter={StaticResource OutlinedValidationErrorTextMarginConverter}}" />
      </DataTrigger>
    </ControlTemplate.Triggers>
  </ControlTemplate>
</ResourceDictionary>