当前位置: 代码迷 >> Silverlight >> [Silverlight入门系列]施用MVVM模式(5):异步Validation数据验证和INotifyDataErrorInfo接口
  详细解决方案

[Silverlight入门系列]施用MVVM模式(5):异步Validation数据验证和INotifyDataErrorInfo接口

热度:6371   发布时间:2013-02-26 00:00:00.0
[Silverlight入门系列]使用MVVM模式(5):异步Validation数据验证和INotifyDataErrorInfo接口

数据验证(Validation)是界面程序的常见需求,例如使用正则表达式验证用户输入的Email地址是否合法,然后在界面给出错误提示信息。在Sivlerlight的MVVM模式中,我们在Model和ViewModel可以做Validation,然后需要把Model和ViewModel的Validation结果和错误信息通知视图(View)。在WPF中,我们使用IDataErrorInfo,在Silverlight4中,建议使用INotifyDataErrorInfo

IDataErrorInfo

先简单说一下IDataErrorInfo,这个接口实现了简单的数据验证和错误报告功能,只能说聊胜于无吧。例子:

?

1 <TextBox Text="{Binding Path=CurrentEmployee.Name, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=True }" />

?

INotifyDataErrorInfo

这个接口只有Silverlight4以上支持,非常强大,支持一个绑定属性多重错误、异步数据验证、自动通知视图错误信息、ErrorChanged事件、HasErrors属性、GetErrors方法等等。定义:

?

1 public interface INotifyDataErrorInfo2 {3 bool HasErrors { get; }4 5 event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;6 7 IEnumerable GetErrors(string propertyName);8 }

?

实现这个INotifyDataErrorInfo接口也非常简单,来个简单的例子:

?

1 public class SimpleModel : INotifyDataErrorInfo 2 { 3 public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; 4 5 private Dictionary<string, List<String>> _errors = new Dictionary<string, List<String>>(); 6 7 private string _accountID = null; 8 9 public string AccountID10 {11 get { return _accountID; }12 set13 {14 if (_accountID != value)15 {16 var propertyName = "AccountID";17 18 if (string.IsNullOrEmpty(value))19 {20 if (!_errors.ContainsKey(propertyName))21 _errors.Add(propertyName, new List<string>());22 23 _errors[propertyName].Add("AccountID can't be null or empty");24 }25 else26 {27 if (_errors.ContainsKey(propertyName))28 _errors.Remove(propertyName);29 }30 31 NotifyErrorsChanged(propertyName);32 33 //Maybe you don't want to set this field to a value if the validation fails34 _accountID = value;35 }36 }37 38 }39 40 public System.Collections.IEnumerable GetErrors(string propertyName)41 {42 if (_errors.ContainsKey(propertyName))43 return _errors[propertyName];44 45 return _errors.Values;46 }47 48 public bool HasErrors49 {50 get { return _errors.Count > 0; }51 }52 53 54 private void NotifyErrorsChanged(string propertyName)55 {56 if (ErrorsChanged != null)57 ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));58 }59 }

?

异步Validation数据验证和INotifyDataErrorInfo接口

这个例子稍微复杂,实现了异步调用WCF RIA Service进行业务逻辑的validation并在ViewModel中把验证的错误提示通知视图,完整的代码下载,需要VS2010和Silverlight环境。

代码说明 ViewModel基类:

?

1 using System; 2 using System.Net; 3 using System.Windows; 4 using System.Linq; 5 using System.Windows.Controls; 6 using System.Windows.Documents; 7 using System.Windows.Ink; 8 using System.Windows.Input; 9 using System.Windows.Media; 10 using System.Windows.Media.Animation; 11 using System.Windows.Shapes; 12 using System.ComponentModel; 13 using System.Collections.Generic; 14 using System.Collections; 15 16 namespace AsycValidation 17 { 18 public class BasicViewModel : INotifyPropertyChanged, INotifyDataErrorInfo 19 { 20 public event PropertyChangedEventHandler PropertyChanged; 21 public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; 22 23 24 private Dictionary<string, List<ValidationErrorInfo>> _errors = 25 new Dictionary<string, List<ValidationErrorInfo>>(); 26 27 28 protected void RemoveErrorFromPropertyAndNotifyErrorChanges( 29 string propertyName, 30 int errorCode) 31 { 32 if (_errors.ContainsKey(propertyName)) 33 { 34 RemoveErrorFromPropertyIfErrorCodeAlreadyExist(propertyName, errorCode); 35 36 NotifyErrorsChanged(propertyName); 37 } 38 } 39 40 private void RemoveErrorFromPropertyIfErrorCodeAlreadyExist( 41 string propertyName, 42 int errorCode) 43 { 44 if (_errors.ContainsKey(propertyName)) 45 { 46 var errorToRemove = _errors[propertyName].SingleOrDefault( 47 error => error.ErrorCode == errorCode); 48 49 if (errorToRemove != null) 50 { 51 _errors[propertyName].Remove(errorToRemove); 52 53 54 55 56 if (_errors[propertyName].Count == 0) 57 _errors.Remove(propertyName); 58 } 59 } 60 } 61 protected void AddErrorToPropertyAndNotifyErrorChanges( 62 string propertyName, 63 ValidationErrorInfo errorInfo) 64 { 65 RemoveErrorFromPropertyIfErrorCodeAlreadyExist(propertyName, errorInfo.ErrorCode); 66 if (!_errors.ContainsKey(propertyName)) 67 _errors.Add(propertyName, new List<ValidationErrorInfo>()); 68 69 _errors[propertyName].Add(errorInfo); 70 71 NotifyErrorsChanged(propertyName); 72 } 73 74 75 public IEnumerable GetErrors(string propertyName) 76 { 77 if (!_errors.ContainsKey(propertyName)) 78 return _errors.Values; 79 80 return _errors[propertyName]; 81 } 82 83 84 public bool HasErrors 85 { 86 get { return this._errors.Count > 0; } 87 } 88 89 90 private void NotifyErrorsChanged(string propertyName) 91 { 92 if (ErrorsChanged != null) 93 ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName)); 94 } 95 96 97 protected void NotifyPropertyChanged(string propertyName) 98 { 99 if (PropertyChanged != null)100 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));101 }102 103 }104 }

?

Model:

?

1 using System; 2 using System.Net; 3 using System.Windows; 4 using System.Windows.Controls; 5 using System.Windows.Documents; 6 using System.Windows.Ink; 7 using System.Windows.Input; 8 using System.Windows.Media; 9 using System.Windows.Media.Animation;10 using System.Windows.Shapes;11 using System.ComponentModel;12 13 namespace AsycValidation14 {15 public class CompanyModel : INotifyPropertyChanged16 {17 public event PropertyChangedEventHandler PropertyChanged;18 19 public int CompanyID { get; set; }20 21 private string _CompanyName;22 public string CompanyName23 {24 get { return _CompanyName; }25 set26 {27 _CompanyName = value;28 29 if (PropertyChanged != null)30 {31 PropertyChanged(this, new PropertyChangedEventArgs("CompanyName"));32 }33 }34 }35 }36 }

?

ViewModel,继承了BaseViewModel基类:

?

1 using System; 2 using System.Net; 3 using System.Windows; 4 using System.Windows.Controls; 5 using System.Windows.Documents; 6 using System.Windows.Ink; 7 using System.Windows.Input; 8 using System.Windows.Media; 9 using System.Windows.Media.Animation;10 using System.Windows.Shapes;11 using AsycValidation.Web;12 13 namespace AsycValidation14 {15 public class CompanyViewModel : BasicViewModel16 {17 public CompanyModel CompanyModelData { get; set; }18 19 public CompanyViewModel(CompanyModel model)20 {21 CompanyModelData = model;22 }23 24 private string _CompanyName = null;25 private const int ACCOUNT_ALREADY_EXIST_ERROCODE = 100;26 27 DomainService1 service = new DomainService1();28 29 public string CompanyName30 {31 get32 {33 return _CompanyName;34 }35 set36 {37 if (_CompanyName != value)38 {39 var propertyName = "CompanyName";40 41 ValidateAccountAlreadyExists(42 value,43 propertyName,44 ACCOUNT_ALREADY_EXIST_ERROCODE,45 string.Format("Company with the ID {0} already exists", value));46 47 _CompanyName = value;48 NotifyPropertyChanged(propertyName);49 }50 }51 }52 53 private void ValidateAccountAlreadyExists(54 string CompanyID,55 string propertyName,56 int errorCode,57 string errorMsg)58 {59 service.DoesCompanyExists(60 CompanyID,61 invokeOperation =>62 {63 if (invokeOperation.Value)64 {65 AddErrorToPropertyAndNotifyErrorChanges(66 propertyName,67 new ValidationErrorInfo()68 {69 ErrorCode = errorCode,70 ErrorMessage = errorMsg71 });72 }73 else74 {75 RemoveErrorFromPropertyAndNotifyErrorChanges(76 propertyName,77 errorCode);78 }79 },80 null);81 }82 83 }84 }

?

View / XAML

?

1 <UserControl x:Class="AsycValidation.MainPage" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:wm="clr-namespace:AsycValidation" 7 mc:Ignorablecolor: #0000f
  相关解决方案