user3778154
user3778154

Reputation: 41

Validation Error template doesn't show the Error result WPF

I am new in WPF I want validate my IP address but I have a problem: when I try to show the error message, it shows me only an empty red border.

Here is the ControlTemplate and all the code:

<Window x:Class="SOTCBindingValidation.Window1"
        x:Name="This"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:SOTCBindingValidation"
        Title="SOTC Validation Test" Height="150" Width="400">
  <Window.Resources>
    <local:ErrorsToMessageConverter x:Key="eToMConverter"/>

    <ControlTemplate x:Key="customvalidatortemplate">
      <StackPanel Orientation="Horizontal">
        <Border BorderThickness="1" BorderBrush="Red" VerticalAlignment="Top">
          <Grid>
            <AdornedElementPlaceholder x:Name="adorner" Margin="-1"/>
          </Grid>
        </Border>
        <Border x:Name="errorBorder" Background="Red" Margin="8,0,0,0"
                CornerRadius="0" IsHitTestVisible="False">
          <TextBlock Text="{Binding ElementName=AddressBox, 
                     Path=(Validation.Errors),
                     Converter={StaticResource eToMConverter}}" 
                     Foreground="White" FontFamily="Segoe UI"
                     Margin="8,2,8,3" TextWrapping="Wrap"
                     VerticalAlignment="Center"/>
        </Border>
      </StackPanel>
    </ControlTemplate>         
  </Window.Resources>

  <StackPanel Margin="5">
    <TextBlock Margin="2">Enter An IPv4 Address:</TextBlock>
    <TextBox x:Name="AddressBox"
             Validation.ErrorTemplate="{StaticResource customvalidatortemplate}"
             Margin="0,0,235.5,0">
      <TextBox.Text>
        <Binding ElementName="This" Path="IPAddress" 
                 UpdateSourceTrigger="PropertyChanged">
          <Binding.ValidationRules>
            <local:IPv4ValidationRule/>
          </Binding.ValidationRules>
        </Binding>
      </TextBox.Text>
    </TextBox>    
  </StackPanel>
</Window>

ErrorsToMessageConverter.cs file :

public class ErrorsToMessageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var sb = new StringBuilder();
        var errors = value as ReadOnlyCollection<ValidationError>;
        if (errors != null)
        {
            foreach (var e in errors.Where(e => e.ErrorContent != null))
            {
                sb.AppendLine(e.ErrorContent.ToString());
            }
        }

        return sb.ToString();
    }

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

IPv4ValidationRule.cs file :

public class IPv4ValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        var str = value as string;
        if (String.IsNullOrEmpty(str))
        {
            return new ValidationResult(false,
                "Please enter an IP Address.");
        }

        var parts = str.Split('.');
        if (parts.Length != 4)
        {
            return new ValidationResult(false,
                "IP Address should be four octets, seperated by decimals.");
        }
        foreach (var p in parts)
        {
            int intPart;
            if (!int.TryParse(p, NumberStyles.Integer, cultureInfo.NumberFormat, out intPart))
            {
                return new ValidationResult(false,
                    "Each octet of an IP Address should be a number.");
            }

            if (intPart < 0 || intPart > 255)
            {
                return new ValidationResult(false,
                    "Each octet of an IP Address should be between 0 and 255.");
            }
        }

        return new ValidationResult(true, null);
    }
}

Upvotes: 0

Views: 1887

Answers (1)

King King
King King

Reputation: 63327

I've found the solution (after a sleep:). In fact the exact element source you have to bind to can be accessed via the AdornedElementPlaceholder. It has a property called AdornedElement, TemplateBinding does not work in this case because TemplatedParent does not point to the TextBox, it's just another Control which is used for ErrorTemplate control. So the code should be like this:

<TextBlock Text="{Binding ElementName=adorner, 
                          Path=AdornedElement.(Validation.Errors),
                          Converter={StaticResource eToMConverter}}" 
           Foreground="White" FontFamily="Segoe UI" Margin="8,2,8,3" 
           TextWrapping="Wrap" VerticalAlignment="Center"/>

Note about how we set the attached property Validation.Errors for the AdornedElement. Also note about the name adorner which is exactly the name you set for the AdornedElementPlaceholder. I've made a demo and surely it should work.

Upvotes: 0

Related Questions