Binding Validation.HasError property in MVVM

The Validation.HasError is readonly property, therefore Binding will not work with this property. This can be seen in ILSpy:

public virtual bool HasError
{
    get
    {
        return this._validationError != null;
    }
}

As an alternative, you should see a great article which provides a solution in the form of use attached dependency properties, there you will see a detailed explanation of the example.

Below is a full example from this article, I just translated it under C#, the original language is VB.NET:

XAML

<Window x:Class="HasErrorTestValidation.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:HasErrorTestValidation"
        WindowStartupLocation="CenterScreen"
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <local:TestData />
    </Window.DataContext>

    <StackPanel>
        <TextBox x:Name="TestTextBox" 
                 local:ProtocolSettingsLayout.MVVMHasError="{Binding Path=HasError}">
            <TextBox.Text>
                <Binding Path="TestText" UpdateSourceTrigger="PropertyChanged">
                    <Binding.ValidationRules>
                        <local:OnlyNumbersValidationRule ValidatesOnTargetUpdated="True"/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>

        <TextBlock>
            <TextBlock.Text>
                <Binding Path="HasError" StringFormat="HasError is {0}"/>
            </TextBlock.Text>
        </TextBlock>

        <TextBlock>
            <TextBlock.Text>
                <Binding Path="(Validation.HasError)" ElementName="TestTextBox" StringFormat="Validation.HasError is {0}"/>
            </TextBlock.Text>
        </TextBlock>        
    </StackPanel>
</Window>

Code-behind

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
}

#region Model

public class TestData : INotifyPropertyChanged
{
    private bool _hasError = false;

    public bool HasError
    {
        get
        {
            return _hasError;
        }

        set
        {
            _hasError = value;
            NotifyPropertyChanged("HasError");
        }
    }

    private string _testText = "0";

    public string TestText
    {
        get
        {
            return _testText;
        }

        set
        {
            _testText = value;
            NotifyPropertyChanged("TestText");
        }
    }

    #region PropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    protected void NotifyPropertyChanged(string sProp)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(sProp));
        }
    }

    #endregion
}

#endregion

#region ValidationRule

public class OnlyNumbersValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        var result = new ValidationResult(true, null);

        string NumberPattern = @"^[0-9-]+$";
        Regex rgx = new Regex(NumberPattern);

        if (rgx.IsMatch(value.ToString()) == false)
        {
            result = new ValidationResult(false, "Must be only numbers");
        }

        return result;
    }
}

#endregion

public class ProtocolSettingsLayout
{       
    public static readonly DependencyProperty MVVMHasErrorProperty= DependencyProperty.RegisterAttached("MVVMHasError", 
                                                                    typeof(bool),
                                                                    typeof(ProtocolSettingsLayout),
                                                                    new FrameworkPropertyMetadata(false, 
                                                                                                  FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                                                                                                  null,
                                                                                                  CoerceMVVMHasError));

    public static bool GetMVVMHasError(DependencyObject d)
    {
        return (bool)d.GetValue(MVVMHasErrorProperty);
    }

    public static void SetMVVMHasError(DependencyObject d, bool value)
    {
        d.SetValue(MVVMHasErrorProperty, value);
    }

    private static object CoerceMVVMHasError(DependencyObject d,Object baseValue)
    {
        bool ret = (bool)baseValue;

        if (BindingOperations.IsDataBound(d,MVVMHasErrorProperty))
        {
            if (GetHasErrorDescriptor(d)==null)
            {
                DependencyPropertyDescriptor desc = DependencyPropertyDescriptor.FromProperty(Validation.HasErrorProperty, d.GetType());
                desc.AddValueChanged(d,OnHasErrorChanged);
                SetHasErrorDescriptor(d, desc);
                ret = System.Windows.Controls.Validation.GetHasError(d);
            }
        }
        else
        {
            if (GetHasErrorDescriptor(d)!=null)
            {
                DependencyPropertyDescriptor desc= GetHasErrorDescriptor(d);
                desc.RemoveValueChanged(d, OnHasErrorChanged);
                SetHasErrorDescriptor(d, null);
            }
        }

        return ret;
    }

    private static readonly DependencyProperty HasErrorDescriptorProperty = DependencyProperty.RegisterAttached("HasErrorDescriptor", 
                                                                            typeof(DependencyPropertyDescriptor),
                                                                            typeof(ProtocolSettingsLayout));

    private static DependencyPropertyDescriptor GetHasErrorDescriptor(DependencyObject d)
    {
        var ret = d.GetValue(HasErrorDescriptorProperty);
        return ret as DependencyPropertyDescriptor;
    }

    private static void OnHasErrorChanged(object sender, EventArgs e)
    {
        DependencyObject d = sender as DependencyObject;

        if (d != null)
        {
            d.SetValue(MVVMHasErrorProperty, d.GetValue(Validation.HasErrorProperty));
        }
    }

   private static void SetHasErrorDescriptor(DependencyObject d, DependencyPropertyDescriptor value)
   {
        var ret = d.GetValue(HasErrorDescriptorProperty);
        d.SetValue(HasErrorDescriptorProperty, value);
    }
}

As an alternative to the use of ValidationRule, in MVVM style you can try to implement IDataErrorInfo Interface. For more info see this:

Enforcing Complex Business Data Rules with WPF