📜  MVVMÂ验证

📅  最后修改于: 2020-11-19 05:25:34             🧑  作者: Mango


在本章中,我们将学习验证。我们还将研究一种干净的方法来验证WPF绑定已支持的内容,并将其绑定到MVVM组件中。

MVVM中的验证

  • 当您的应用程序开始接受来自最终用户的数据输入时,您需要考虑验证该输入。

  • 确保它符合您的总体要求。

  • WPF在绑定系统中具有一些很棒的构建和功能,用于验证输入,并且在执行MVVM时,您仍然可以利用所有这些功能。

  • 请记住,支持您的验证并定义哪些规则存在的逻辑应该属于Model或ViewModel的一部分,而不是View本身。

您仍然可以使用WPF数据绑定支持的所有表达验证的方式,包括-

  • 设置了对属性的抛出异常。
  • 实现IDataErrorInfo接口。
  • 实现INotifyDataErrorInfo。
  • 使用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); } 
      } 
   } 
}

编译并执行上述代码后,您将看到以下窗口。

MVVM验证MainWindow1

当您按下添加客户按钮时,您将看到以下视图。当用户将任何字段留空时,该字段将突出显示,并且保存按钮将被禁用。

MVVM验证MainWindow2