Shu*_*huo 12 c# validation wpf
实施的最佳做法是IDataErrorInfo什么?反正有没有硬编码的字符串属性名称来实现它?
Nic*_*cki 13
如果你在实现中做了一些改进,你可以使用DataAnnotationsIDataErrorInfo.例如,这是我经常使用的基本视图模型(从Windows窗体,但您可以推断):
public class ViewModelBase : IDataErrorInfo, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public SynchronizationContext Context
{
get;
set;
}
public bool HasErrors
{
get
{
return !string.IsNullOrWhiteSpace(this.Error);
}
}
public string Error
{
get
{
var type = this.GetType();
var modelClassProperties = TypeDescriptor
.GetProperties(type)
.Cast();
return
(from modelProp in modelClassProperties
let error = this[modelProp.Name]
where !string.IsNullOrWhiteSpace(error)
select error)
.Aggregate(new StringBuilder(), (acc, next) => acc.Append(" ").Append(next))
.ToString();
}
}
public virtual string this[string columnName]
{
get
{
var type = this.GetType();
var modelClassProperties = TypeDescriptor
.GetProperties(type)
.Cast();
var errorText =
(from modelProp in modelClassProperties
where modelProp.Name == columnName
from attribute in modelProp.Attributes.OfType()
from displayNameAttribute in modelProp.Attributes.OfType()
where !attribute.IsValid(modelProp.GetValue(this))
select attribute.FormatErrorMessage(displayNameAttribute == null ? modelProp.Name : displayNameAttribute.DisplayName))
.FirstOrDefault();
return errorText;
}
}
protected void NotifyPropertyChanged(string propertyName)
{
if (string.IsNullOrWhiteSpace(propertyName))
{
throw new ArgumentNullException("propertyName");
}
if (!this.GetType().GetProperties().Any(x => x.Name == propertyName))
{
throw new ArgumentException(
"The property name does not exist in this type.",
"propertyName");
}
var handler = this.PropertyChanged;
if (handler != null)
{
if (this.Context != null)
{
this.Context.Post(obj => handler(this, new PropertyChangedEventArgs(propertyName)), null);
}
else
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}Run Code Online (Sandbox Code Playgroud)
示例用法:
public class LogOnViewModel : ViewModelBase
{
[DisplayName("User Name")]
[Required]
[MailAddress] // This is a custom DataAnnotation I wrote
public string UserName
{
get
{
return this.userName;
}
set
{
this.userName = value;
this.NotifyPropertyChanged("UserName");
}
}
[DisplayName("Password")]
[Required]
public string Password
{
get; // etc
set; // etc
}
}
Run Code Online (Sandbox Code Playgroud)
说实话,我最终使用了注释和开关.我使用注释进行简单验证,如果我有更复杂的注释(例如"如果设置了其他属性,则只验证此属性"),那么我将在this[]索引的覆盖中求助于切换.这种模式经常看起来像这样(只是一个例子,它没有意义:
public override string this[string columnName]
{
get
{
// Let the base implementation run the DataAnnotations validators
var error = base[columnName];
// If no error reported, run my custom one-off validations for this
// view model here
if (string.IsNullOrWhiteSpace(error))
{
switch (columnName)
{
case "Password":
if (this.Password == "password")
{
error = "See an administrator before you can log in.";
}
break;
}
}
return error;
}
Run Code Online (Sandbox Code Playgroud)
至于将属性名称指定为字符串:你可以用lambdas做一些奇特的事情,但我诚实的建议就是克服它.您可能会注意到,在我的帮助下ViewModelBase,我的小NotifyPropertyChanged助手会做一些反射魔法,以确保我没有胖指的属性名称 - 这有助于我快速检测到数据绑定错误,而不是绕过20分钟搞清楚我是什么我错过了.
您的应用程序将进行一系列验证,从UI属性级别的"必需"或"最大长度"等"piddly"到"在其他UI级别检查其他内容时需要"并且一直到域/持久性级别中的"用户名不存在".您会发现,在UI中重复一点验证逻辑与在域中添加大量元数据以向UI描述自身之间,您将不得不进行权衡,并且您将不得不在如何权衡这些逻辑上进行权衡.向用户显示不同类别的验证错误.
希望有所帮助.祝好运!
| 归档时间: |
|
| 查看次数: |
6200 次 |
| 最近记录: |