How to display an error message for DataAnnotations

I spent the last hour or so searching for an answer to this question, but almost every result - either in ASP.NET, or talks about Code First approaches that are useless to me.

Basically, I got POCO objects for database entity objects that I provide to validate the use of IDataErrorInfo.

Now this works fine, except that I have a pointer that is 200 lines long with approximately 40 if-statements. (I'm serious.)

What I'm doing right now extends classes as follows:

public partial class MyPocoObject : IDataErrorInfo
{
    public string Error
    {
        get { throw new NotImplementedException("IDataErrorInfo.Error"); }
    }

    public string this[string columnName]
    {
        get
        {
            string result = null;

            // There about 40 if statements here...
        }
    }
}

This is clearly wrong, so I'm trying to use DataAnnotations.

This is what I understood so far.

I have created such metadata classes:

[MetadataType(typeof(MyObjectMetaData))]
public partial class MyObject { }

public class MyObjectMetaData
{
    [Required(AllowEmptyStrings = false, ErrorMessage = "Forename is a required field.")]
    public string Forename;
}

Then I have controls declared as such:

<TextBox Text="{Binding SelectedObject.Forename, NotifyOnValidationError=True, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/>

:

<Style TargetType="TextBox" BasedOn="{StaticResource Global}">
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="true">
            <Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self},Path=(Validation.Errors)[0].ErrorContent}"/>
        </Trigger>
    </Style.Triggers>
</Style>

IDataErrorInfo, , . , .

? 40 if .

Update: , , , , .

public partial class Member : IDataErrorInfo
{
    // Error: The type 'Project.Client.Models.Member' already contains a definition for 'Forename'
    [Required(AllowEmptyStrings = false, ErrorMessage = "Forename is a required field.")]
    public string Forename;

    private readonly Dictionary<string, object> _values = new Dictionary<string, object>();

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

    public string this[string columnName]
    {
        get { return OnValidate(columnName); }
    }


    protected virtual string OnValidate(string propertyName)
    {
        if (string.IsNullOrEmpty(propertyName))
        {
            throw new ArgumentException("Invalid property name", propertyName);
        }

        string error = string.Empty;
        // Error: Project.Client.Models.Member.GetValue<T>(string)' cannot be inferred from the usage. Try specifying the type arguments explicitly
        var value = GetValue(propertyName);
        var results = new List<System.ComponentModel.DataAnnotations.ValidationResult>(1);
        var result = Validator.TryValidateProperty(
            value,
            new ValidationContext(this, null, null)
            {
                MemberName = propertyName
            },
            results);

        if (!result)
        {
            var validationResult = results.First();
            error = validationResult.ErrorMessage;
        }

        return error;
    }

    protected T GetValue<T>(string propertyName)
    {
        if (string.IsNullOrEmpty(propertyName))
        {
            throw new ArgumentException("Invalid property name", propertyName);
        }

        object value;
        if (!_values.TryGetValue(propertyName, out value))
        {
            value = default(T);
            _values.Add(propertyName, value);
        }

        return (T)value;
    }
}

2: , MVVM, , , , OnValidate .

- ... , , , GetValue, , , , .

+4
3

, viewmodel, , , .

, , , ....

0

, DataAnnotations . , System.ComponentModel.DataAnnotations.Validator MetadataType , TypeDescriptor, , .

Article Code

, System.ComponentModel.DataAnnotations.Validator.

PropertyChangedNotification , :

/// <summary>
        /// Validates current instance properties using Data Annotations.
        /// </summary>
        /// <param name="propertyName">This instance property to validate.</param>
        /// <returns>Relevant error string on validation failure or <see cref="System.String.Empty"/> on validation success.</returns>
        protected virtual string OnValidate(string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName))
            {
                throw new ArgumentException("Invalid property name", propertyName);
            }

            string error = string.Empty;
            var value = GetValue(propertyName);
            var results = new List<System.ComponentModel.DataAnnotations.ValidationResult>(1);
            var result = Validator.TryValidateProperty(
                value,
                new ValidationContext(this, null, null)
                {
                    MemberName = propertyName
                },
                results);

            if (!result)
            {
                var validationResult = results.First();
                error = validationResult.ErrorMessage;
            }

            return error;
        }
+1

.NET , - . :

var myObjectMetadaProviderProvider = new AssociatedMetadataTypeTypeDescriptionProvider(typeof(MyObject), typeof(MyObjectMetaData));
TypeDescriptor.AddProvider(myObjectMetadaProviderProvider , typeof(MyObject));

This allows you to transparently retrieve attributes declared in friend classes without having to know about the metadata in the main class.

0
source

All Articles