I have a partial EF class Applicant and the following
[MetadataType(typeof(ApplicantMetadata))]
public partial class Applicant : ValidatableBindableBase
{
static Applicant()
{
TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(typeof(Applicant),
typeof(ApplicantMetadata)),
typeof(Applicant));
}
internal sealed class ApplicantMetadata
{
[Required]
public int APPLICANT_ID;
[Required]
[StringLength(100)]
public string APPLICANT_Title;
[Required]
[StringLength(10)]
public string APPLICANT_Forename;
[Required]
[StringLength(10)]
public string APPLICANT_Surname;
public ApplicantMetadata()
{
}
}
The class it inherits from is
using Microsoft.Practices.Prism.Mvvm;
using Microsoft.Practices.Prism.ViewModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
using System.Runtime.CompilerServices;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using System.Linq.Expressions;
namespace ValidatableBindableBaseDemo
{
public class ValidatableBindableBase : BindableBase, INotifyDataErrorInfo
{
ErrorsContainer<string> _errorsContainer;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged = delegate { };
public IEnumerable GetErrors(string propertyName)
{
return ErrorsContainer.GetErrors(propertyName);
}
public void SetErrors<TProperty>(Expression<Func<TProperty>> propertyExpression, IEnumerable<string> errors)
{
ErrorsContainer.SetErrors(propertyExpression, errors);
}
public bool HasErrors
{
get { return ErrorsContainer.HasErrors; }
}
public Dictionary<string, List<string>> GetAllErrors()
{
return ErrorsContainer.GetAllErrors();
}
protected ErrorsContainer<string> ErrorsContainer
{
get
{
if (_errorsContainer == null)
{
_errorsContainer =
new ErrorsContainer<string>(pn => this.RaiseErrorsChanged(pn));
}
return _errorsContainer;
}
}
private void RaiseErrorsChanged(string propertyName)
{
OnErrorsChanged(new DataErrorsChangedEventArgs(propertyName));
}
protected virtual void OnErrorsChanged(DataErrorsChangedEventArgs e)
{
ErrorsChanged(this, e);
}
protected override bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
var result = base.SetProperty(ref storage, value, propertyName);
if (result && !string.IsNullOrEmpty(propertyName))
{
ValidateProperty(propertyName);
}
return result;
}
public bool ValidateProperty(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
{
throw new ArgumentNullException("propertyName");
}
var propertyInfo = this.GetType().GetRuntimeProperty(propertyName);
if (propertyInfo == null)
{
throw new ArgumentException("Invalid property name", propertyName);
}
var propertyErrors = new List<string>();
bool isValid = TryValidateProperty(propertyInfo, propertyErrors);
ErrorsContainer.SetErrors(propertyInfo.Name, propertyErrors);
return isValid;
}
public bool ValidateProperties()
{
var propertiesWithChangedErrors = new List<string>();
// Get all the properties decorated with the ValidationAttribute attribute.
var propertiesToValidate = this.GetType()
.GetRuntimeProperties()
.Where(c => c.GetCustomAttributes(typeof(ValidationAttribute)).Any());
foreach (PropertyInfo propertyInfo in propertiesToValidate)
{
var propertyErrors = new List<string>();
TryValidateProperty(propertyInfo, propertyErrors);
// If the errors have changed, save the property name to notify the update at the end of this method.
ErrorsContainer.SetErrors(propertyInfo.Name, propertyErrors);
}
return ErrorsContainer.HasErrors;
}
private bool TryValidateProperty(PropertyInfo propertyInfo, List<string> propertyErrors)
{
var results = new List<ValidationResult>();
var context = new ValidationContext(this) { MemberName = propertyInfo.Name };
var propertyValue = propertyInfo.GetValue(this);
// Validate the property
bool isValid = Validator.TryValidateProperty(propertyValue, context, results);
if (results.Any())
{
propertyErrors.AddRange(results.Select(c => c.ErrorMessage));
}
return isValid;
}
}
}
As a check I have a command which simply calls Applicant.ValidateProperties();
The problem is
var propertiesToValidate = GetType().GetRuntimeProperties()
.Where(c => c.GetCustomAttributes(typeof(ValidationAttribute)).Any());
returns no properties - any ideas?