Я построил базовый класс для моделей моего вида. Вот некоторые кода:
public class BaseViewModel<TModel> : DependencyObject, INotifyPropertyChanged, IDisposable, IBaseViewModel<TModel>, IDataErrorInfo
{
public TModel Model { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (this._disposed)
{
return;
}
if (disposing)
{
this.Model = default(TModel);
}
this._disposed = true;
}
}
Хорошо, я подумал, давайте добавим некоторую проверку в базовый класс, что привело меня к следующей статье: Проверка Prism IDataErrorInfo с DataAnnotation в объектах ViewModel . Поэтому я добавил следующие методы / свойства (IDataErrorInfo) в свой базовый класс:
string IDataErrorInfo.Error
{
get { return null; }
}
string IDataErrorInfo.this[string columnName]
{
get { return ValidateProperty(columnName); }
}
protected virtual string ValidateProperty(string columnName)
{
// get cached property accessors
var propertyGetters = GetPropertyGetterLookups(GetType());
if (propertyGetters.ContainsKey(columnName))
{
// read value of given property
var value = propertyGetters[columnName](this);
// run validation
var results = new List<ValidationResult>();
var vc = new ValidationContext(this, null, null) { MemberName = columnName };
Validator.TryValidateProperty(value, vc, results);
// transpose results
var errors = Array.ConvertAll(results.ToArray(), o => o.ErrorMessage);
return string.Join(Environment.NewLine, errors);
}
return string.Empty;
}
private static Dictionary<string, Func<object, object>> GetPropertyGetterLookups(Type objType)
{
var key = objType.FullName ?? "";
if (!PropertyLookupCache.ContainsKey(key))
{
var o = objType.GetProperties()
.Where(p => GetValidations(p).Length != 0)
.ToDictionary(p => p.Name, CreatePropertyGetter);
PropertyLookupCache[key] = o;
return o;
}
return (Dictionary<string, Func<object, object>>)PropertyLookupCache[key];
}
private static Func<object, object> CreatePropertyGetter(PropertyInfo propertyInfo)
{
var instanceParameter = System.Linq.Expressions.Expression.Parameter(typeof(object), "instance");
var expression = System.Linq.Expressions.Expression.Lambda<Func<object, object>>(
System.Linq.Expressions.Expression.ConvertChecked(
System.Linq.Expressions.Expression.MakeMemberAccess(
System.Linq.Expressions.Expression.ConvertChecked(instanceParameter, propertyInfo.DeclaringType),
propertyInfo),
typeof(object)),
instanceParameter);
var compiledExpression = expression.Compile();
return compiledExpression;
}
private static ValidationAttribute[] GetValidations(PropertyInfo property)
{
return (ValidationAttribute[])property.GetCustomAttributes(typeof(ValidationAttribute), true);
}
Хорошо, это подводит меня к вопросу. Дело в том, что проверка работает отлично, но, допустим, у меня есть свойство (в моей модели представления с именем: Person) с атрибутом StringLength. Атрибут StringLength срабатывает, как только приложение открывается. У пользователя даже не было возможности что-либо сделать. Проверка запускается, как только приложение запускается.
public class PersonViewModel : BaseViewModel<BaseProxyWrapper<PosServiceClient>>
{
private string _password = string.Empty;
[StringLength(10, MinimumLength = 3, ErrorMessage = "Password must be between 3 and 10 characters long")]
public string Password
{
get { return this._password; }
set
{
if (this._password != value)
{
this._password = value;
this.OnPropertyChanged("Password");
}
}
}
}
Я заметил, что это вызвано свойством IDataErrorInfo.this[string columnName]
и, в свою очередь, вызывает метод ValidateProperty
. Но я понятия не имею, как это исправить?