D.Weder
D.Weder

Reputation: 307

How to do a simple validation with IDataErrorInfo and data annotations

I have Model with one property. This Model inherits from a base model which implements INotifyPropertyChanged and IDataInfoError. Above my property I have ValidationAttribute Required, with an error message I want to bring into a tooltip. Therefore I have a textbox in my view.

My proplem: When the textbox is empty, the validation works. The textbox has a red border. When the textbox is empty and I write something in it, I get a error in my output window.

System.Windows.Data Error: 17 : Cannot get 'Item[]' value (type 'ValidationError') from '(Validation.Errors)' (type 'ReadOnlyObservableCollection`1'). BindingExpression:Path=(0)[0].ErrorContent; DataItem='TextBox' (Name=''); target element is 'TextBox' (Name=''); target property is 'ToolTip' (type 'Object') ArgumentOutOfRangeException:'System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. Parameter name: index'

To reproduce the error: Models

public class ModelBase : INotifyPropertyChanged, IDataErrorInfo
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public string Error { get { return null; } }

    public string this[string columnName]
    {
        get
        {
            var validationResults = new List<ValidationResult>();

            if (Validator.TryValidateProperty(
                    GetType().GetProperty(columnName).GetValue(this)
                    , new ValidationContext(this) { MemberName = columnName }
                    , validationResults))
                return null;

            return validationResults.First().ErrorMessage;
        }
    }
}

public class Model : ModelBase
{
    private string name;

    [Required(ErrorMessage = "Wrong")]
    public string Name
    {
        get { return name; }
        set
        {
            name = value;

            OnPropertyChanged();
        }
    }
}

View

<Window.Resources>
    <Style TargetType="{x:Type TextBox}">
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="True">
                <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self},
                    Path=(Validation.Errors)[0].ErrorContent}" />
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
<StackPanel>
    <TextBox Margin="10" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, NotifyOnValidationError=True, Mode=TwoWay}"></TextBox>
</StackPanel>

Upvotes: 0

Views: 469

Answers (1)

mm8
mm8

Reputation: 169160

There is no ValidationError at position 0 when your indexer returns null. Binding to (Validation.Errors).CurrentItem.ErrorContent instead of (Validation.Errors)[0].ErrorContent should fix the binding error:

<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self},
                    Path=(Validation.Errors).CurrentItem.ErrorContent}" />

Upvotes: 1

Related Questions