gpt4 book ai didi

wpf - 验证触发太早

转载 作者:行者123 更新时间:2023-12-03 10:30:06 26 4
gpt4 key购买 nike

我已经为我的 View 模型构建了一个基类。这里是 一些代码:

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 validation with DataAnnotation on ViewModel Entities .所以我在我的基类中添加了以下方法/属性(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);
}

好的,这让我想到了这个问题。问题是验证工作完美,但可以说我有一个带有 StringLength 属性的属性(在我的 View 模型中称为:Person)。 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方法。但是,我不知道如何解决这个问题?

最佳答案

可能有两个问题...

您是否填充 yopur Person使用公共(public)属性的实例?

例如

  new Person { Password = null }

这将触发 Password 的属性更改通知并对其进行验证。

一些开发人员还在构造函数中设置属性...
public class Person {
public Person() {
this.Password = null;
}
}

推荐的做法是使用私有(private)字段...
public class Person {
public Person() {
_password = null;
}

public Person(string pwd) {
_password = pwd;
}
}

或者

您可以在我们的 View 模型库中创建一个标志,例如 IsLoaded .确保仅在加载 UI 后将其设置为 true(可能在 UI.Loaded 事件中)。在您的 IDataErrorInfo.this[string columnName]检查此属性是否为真,然后才验证值。否则返回null。

[编辑]

以下更改完成了这项工作:
public class PersonViewModel : BaseViewModel<BaseProxyWrapper<PosServiceClient>>
{
private string _password;
[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");
}
}
}

public PersonViewModel(BaseProxyWrapper<PosServiceClient> model)
: base(model)
{
this._username = null;
}
}

关于wpf - 验证触发太早,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7967111/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com