我完全按照以下链接中的描述实现了INotifyDataErrorInfo:
http://blog.micic.ch/net/easy-mvvm-example-with-inotifypropertychanged-and-inotifydataerrorinfo
我有一个TextBox
绑定到我的模型中的字符串属性.
XAML
模型
private string _fullName; public string FullName { get { return _fullName; } set { // Set raises OnPropertyChanged Set(ref _fullName, value); if (string.IsNullOrWhiteSpace(_fullName)) AddError(nameof(FullName), "Name required"); else RemoveError(nameof(FullName)); } }
INotifyDataError代码
private Dictionary> _errors = new Dictionary >(); public event EventHandler ErrorsChanged; // get errors by property public IEnumerable GetErrors(string propertyName) { if (_errors.ContainsKey(propertyName)) return _errors[propertyName]; return null; } public bool HasErrors => _errors.Count > 0; // object is valid public bool IsValid => !HasErrors; public void AddError(string propertyName, string error) { // Add error to list _errors[propertyName] = new List () { error }; NotifyErrorsChanged(propertyName); } public void RemoveError(string propertyName) { // remove error if (_errors.ContainsKey(propertyName)) _errors.Remove(propertyName); NotifyErrorsChanged(propertyName); } public void NotifyErrorsChanged(string propertyName) { // Notify if (ErrorsChanged != null) ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName)); }
现在这一切都运行正常,但只有在我的TextBox中输入内容时才会验证.我想要一些方法来按需验证,甚至没有触摸文本框,比如按一下按钮.
我已经尝试过为我的所有属性提升PropertyChanged,如本问题所述,但它没有检测到错误.我不知何故需要调用我的属性设置器,以便可以检测到错误.我正在寻找一个MVVM解决方案.
你使用的INotifyDataErrorInfo实现有点瑕疵恕我直言.它依赖于附加到对象的状态(列表)中保存的错误.存储状态的问题有时在移动的世界中,您没有机会在需要时更新它.这是另一个MVVM实现,它不依赖于存储状态,但可以动态计算错误状态.
由于您需要将验证代码放在一个集中的GetErrors方法中(您可以创建从此中心方法调用的每个属性验证方法),而不是在属性设置器中,因此处理的方式有所不同.
public class ModelBase : INotifyPropertyChanged, INotifyDataErrorInfo { public event PropertyChangedEventHandler PropertyChanged; public event EventHandlerErrorsChanged; public bool HasErrors { get { return GetErrors(null).OfType
这里有两个示例类,演示如何使用它:
public class Customer : ModelBase { private string _name; public string Name { get { return _name; } set { if (_name != value) { _name = value; OnPropertyChanged(); } } } public override IEnumerable GetErrors([CallerMemberName] string propertyName = null) { if (string.IsNullOrEmpty(propertyName) || propertyName == nameof(Name)) { if (string.IsNullOrWhiteSpace(_name)) yield return "Name cannot be empty."; } } } public class CustomerWithAge : Customer { private int _age; public int Age { get { return _age; } set { if (_age != value) { _age = value; OnPropertyChanged(); } } } public override IEnumerable GetErrors([CallerMemberName] string propertyName = null) { foreach (var obj in base.GetErrors(propertyName)) { yield return obj; } if (string.IsNullOrEmpty(propertyName) || propertyName == nameof(Age)) { if (_age <= 0) yield return "Age is invalid."; } } }
它就像一个带有简单XAML的魅力,如下所示:
(UpdateSourceTrigger是可选的,如果你不使用它,它只会在焦点丢失时起作用).
使用此MVVM基类,您不必强制进行任何验证.但是,如果你需要它,我在ModelBase中添加了一个ForceValidation示例方法应该可以工作(我已经测试了它,例如像_name这样的成员值,如果没有通过公共setter就会被更改).