📅  最后修改于: 2020-11-19 05:25:34             🧑  作者: Mango
在本章中,我们将学习验证。我们还将研究一种干净的方法来验证WPF绑定已支持的内容,并将其绑定到MVVM组件中。
当您的应用程序开始接受来自最终用户的数据输入时,您需要考虑验证该输入。
确保它符合您的总体要求。
WPF在绑定系统中具有一些很棒的构建和功能,用于验证输入,并且在执行MVVM时,您仍然可以利用所有这些功能。
请记住,支持您的验证并定义哪些规则存在的逻辑应该属于Model或ViewModel的一部分,而不是View本身。
您仍然可以使用WPF数据绑定支持的所有表达验证的方式,包括-
通常,建议使用INotifyDataErrorInfo并将其引入WPF .net 4.5,它支持查询对象中与属性相关的错误,并且还解决了所有其他选项的一些不足。具体来说,它允许异步验证。它允许属性具有多个与之相关的错误。
让我们看一个示例,在该示例中,我们将验证支持添加到输入视图中,在大型应用程序中,您可能需要在应用程序中放置多个位置。有时在视图上,有时在ViewModels上,有时在这些辅助对象上,模型对象周围都有包装器。
将验证支持放在一个通用的基类中,然后可以从不同的方案中继承它是一种很好的做法。
基类将支持INotifyDataErrorInfo,以便在属性更改时触发验证。
创建后添加一个名为ValidatableBindableBase的新类。由于我们已经有一个用于属性更改处理的基类,因此让我们从该基类派生该基类并实现INotifyDataErrorInfo接口。
以下是ValidatableBindableBase类的实现。
using System;
using System.Collections.Generic;
using System.ComponentModel;
//using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
namespace MVVMHierarchiesDemo {
public class ValidatableBindableBase : BindableBase, INotifyDataErrorInfo {
private Dictionary> _errors = new Dictionary>();
public event EventHandler
ErrorsChanged = delegate { };
public System.Collections.IEnumerable GetErrors(string propertyName) {
if (_errors.ContainsKey(propertyName))
return _errors[propertyName];
else
return null;
}
public bool HasErrors {
get { return _errors.Count > 0; }
}
protected override void SetProperty(ref T member, T val,
[CallerMemberName] string propertyName = null) {
base.SetProperty(ref member, val, propertyName);
ValidateProperty(propertyName, val);
}
private void ValidateProperty(string propertyName, T value) {
var results = new List();
//ValidationContext context = new ValidationContext(this);
//context.MemberName = propertyName;
//Validator.TryValidateProperty(value, context, results);
if (results.Any()) {
//_errors[propertyName] = results.Select(c => c.ErrorMessage).ToList();
} else {
_errors.Remove(propertyName);
}
ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
}
}
}
现在,在相应的文件夹中添加AddEditCustomerView和AddEditCustomerViewModel。以下是AddEditCustomerView.xaml的代码。
以下是AddEditCustomerViewModel实现。
using MVVMHierarchiesDemo.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MVVMHierarchiesDemo.ViewModel {
class AddEditCustomerViewModel : BindableBase {
public AddEditCustomerViewModel() {
CancelCommand = new MyIcommand(OnCancel);
SaveCommand = new MyIcommand(OnSave, CanSave);
}
private bool _EditMode;
public bool EditMode {
get { return _EditMode; }
set { SetProperty(ref _EditMode, value);}
}
private SimpleEditableCustomer _Customer;
public SimpleEditableCustomer Customer {
get { return _Customer; }
set { SetProperty(ref _Customer, value);}
}
private Customer _editingCustomer = null;
public void SetCustomer(Customer cust) {
_editingCustomer = cust;
if (Customer != null) Customer.ErrorsChanged -= RaiseCanExecuteChanged;
Customer = new SimpleEditableCustomer();
Customer.ErrorsChanged += RaiseCanExecuteChanged;
CopyCustomer(cust, Customer);
}
private void RaiseCanExecuteChanged(object sender, EventArgs e) {
SaveCommand.RaiseCanExecuteChanged();
}
public MyIcommand CancelCommand { get; private set; }
public MyIcommand SaveCommand { get; private set; }
public event Action Done = delegate { };
private void OnCancel() {
Done();
}
private async void OnSave() {
Done();
}
private bool CanSave() {
return !Customer.HasErrors;
}
}
}
以下是SimpleEditableCustomer类的实现。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MVVMHierarchiesDemo.Model {
public class SimpleEditableCustomer : ValidatableBindableBase {
private Guid _id;
public Guid Id {
get { return _id; }
set { SetProperty(ref _id, value); }
}
private string _firstName;
[Required]
public string FirstName {
get { return _firstName; }
set { SetProperty(ref _firstName, value); }
}
private string _lastName;
[Required]
public string LastName {
get { return _lastName; }
set { SetProperty(ref _lastName, value); }
}
private string _email;
[EmailAddress]
public string Email {
get { return _email; }
set { SetProperty(ref _email, value); }
}
private string _phone;
[Phone]
public string Phone {
get { return _phone; }
set { SetProperty(ref _phone, value); }
}
}
}
编译并执行上述代码后,您将看到以下窗口。
当您按下添加客户按钮时,您将看到以下视图。当用户将任何字段留空时,该字段将突出显示,并且保存按钮将被禁用。