简单数据注释验证未显示在视图中(无红色网格线)

时间:2015-10-03 12:24:32

标签: c# wpf entity-framework xaml

我正在使用Entity Framework。

根据这个:https://msdn.microsoft.com/en-us/data/gg193959.aspx

  

“在应用程序中没有其他代码或标记更改,a   现有的MVC应用程序将执行客户端验证“

绑定是正确的。

验证不会过滤到DataGrid,我在SaveChanges上得到一个例外。

模型

private string _Sponsor;
[Required]
[StringLength(20, MinimumLength = 3)]
public string Sponsor
{
    get
    {
        return _Sponsor;
    }
    set
    {
        _Sponsor = value;
        NotifyPropertyChanged("Sponsor");
    }
}

MainWindow.xaml.cs

JobCollectionContext _context = new JobCollectionContext();

CollectionViewSource jobViewSource = ((CollectionViewSource)(this.FindResource("jobViewSource")));

_context.JobCollection.Load();

jobViewSource.Source = _context.JobCollection.Local;

MainWindow.xaml

<DataGridTextColumn Header="Sponsor" Binding="{Binding Sponsor, UpdateSourceTrigger=LostFocus, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" />

1 个答案:

答案 0 :(得分:3)

因为这不是MVC应用程序。您正在开发WPF应用程序。

如果要在WPF应用程序中显示错误,则需要实现接口INotifyDataErrorInfo

我有一个实现必要逻辑的基类。只需继承它并调用ValidateProperty("propertyName"),它就会使用Attributes来验证给定的属性。

您应该在所有应该验证的属性集中执行此操作,例如使用NotifyPropertyChanged()进行更新以保持UI更新。

public abstract class NotifyDataErrorModel : INotifyDataErrorInfo
{
    /// <summary>
    /// Maps properties to their error sets
    /// </summary>
    protected Dictionary<string, HashSet<string>> errors;
    /// <summary>
    /// maps a property to a list of properties 
    /// the list of properties will get the ValidationErrors of the property
    /// </summary>
    protected NotifyDataErrorModel()
    {
        errors = new Dictionary<string, HashSet<string>>();
        var properties = getProperties();
        foreach (var property in properties)
        {
            errors.Add(property, new HashSet<string>());
        }
    }

    private IEnumerable<string> getProperties()
    {
        var properties = this.GetType().GetProperties().Select(p => p.Name).ToList();
        properties.Remove("HasErrors"); //remove the HasErrors property, because it is part of the interface INotifyDataErrorInfo and not of the actual model
        return properties;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="property">the property to validate</param>
    public virtual void ValidateProperty(string property)
    {
        //clear the errors on the matched property
        errors[property].Clear();

        var type = this.GetType();
        //the entity framework proxies sometimes dont inherit the attributes of the properties
        //so if it is a entity framework proxy object, get the base class (which is the actual model class) instead
        if (type.FullName.Contains("System.Data.Entity.DynamicProxies"))
        {
            type = type.BaseType;
        }
        var propertyInfo = type.GetProperty(property);
        var propertyValue = propertyInfo.GetValue(this);
        var validationAttributes = propertyInfo.GetCustomAttributes(true).OfType<ValidationAttribute>();
        foreach (var validationAttribute in validationAttributes)
        {
            if (!validationAttribute.IsValid(propertyValue))
            {
                errors[property].Add(validationAttribute.FormatErrorMessage(string.Empty));
            }
        }
        raiseErrorsChanged(property);
    }

    public virtual void ValidateAllProperties()
    {
        var properties = getProperties();
        foreach (var property in properties) ValidateProperty(property);
    }

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    public System.Collections.IEnumerable GetErrors(string propertyName)
    {
        //if the propertyname is not valid, return an empty IEnumerable
        if (String.IsNullOrEmpty(propertyName)) return new List<string>();

        return errors[propertyName];
    }

    public bool HasErrors
    {
        get { return errors.Any((propertyErrors) => propertyErrors.Value.Count > 0); }
    }

    private void raiseErrorsChanged(string property)
    {
        if (ErrorsChanged != null)
        {
            var eventArgs = new DataErrorsChangedEventArgs(property);
            ErrorsChanged(this, eventArgs);
        }
    }
}