[Silverlight入门系列]使用MVVM模式(5):异步Validation数据验证和INotifyDataErrorInfo接口
- 博客分类:
- MVVM
数据验证(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 INotifyDataErrorInfo 2 { 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 AccountID 10 { 11 get { return _accountID; } 12 set 13 { 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 else 26 { 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 fails 34 _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 HasErrors 49 { 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 AsycValidation 14 { 15 public class CompanyModel : INotifyPropertyChanged 16 { 17 public event PropertyChangedEventHandler PropertyChanged; 18 19 public int CompanyID { get; set; } 20 21 private string _CompanyName; 22 public string CompanyName 23 { 24 get { return _CompanyName; } 25 set 26 { 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 AsycValidation 14 { 15 public class CompanyViewModel : BasicViewModel 16 { 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 CompanyName 30 { 31 get 32 { 33 return _CompanyName; 34 } 35 set 36 { 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 = errorMsg 71 }); 72 } 73 else 74 { 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发表评论
-
[Silverlight入门系列]使用MVVM模式(7):ViewModel的INotifyPropertyChanged接口实现
2011-06-06 20:44 1413上一篇说到《Model的INotifyPropertyCh ... -
[Silverlight入门系列]使用MVVM模式(6):使用Behavior
2011-06-06 20:42 1593Behavior把一些常用的行为封装成可重复使用的组件(C ... -
[Silverlight入门系列]使用MVVM模式(4):Prism的NotificationObject自动实现INotifyPropertyChanged接
2011-06-06 20:37 1370在上一篇写了Model的INotifyPropertyChan ... -
[Silverlight入门系列]使用MVVM模式(3):Model的INotifyPropertyChanged接口实现
2011-06-06 20:36 962当客户端绑定一个数据模型以后,数据模型变化以后可以自动通知 ... -
[Silverlight入门系列]使用MVVM模式(2):集合
2011-06-06 20:33 1152Model /ObservableCollection/ICo ... -
[Silverlight入门系列]使用MVVM模式(1):MVVM核心概念
2011-06-06 20:26 1591MVVM模式是Model、View、ViewModel的简称, ...
相关推荐
如何创建更好的Silverlight程序系列课程(3):Silverlight & MVVM
对于初学silverlight很有帮助,对silverlight的验证机制和MVVM的模式得到初步的了解。
Silverlight MVVM模式Silverlight MVVM模式Silverlight MVVM模式
"MVVM in Delphi: Architecting and Building Model View ViewModel Applications" 2016 | ISBN-10: 148422213X | 143 pages | PDF, EPUB | 23 MB Dive into the world of MVVM, learn how to build modern ...
silverlight 中mvvm 的使用详解
该资源使用MVVM编程模式,页面与逻辑分离的情况下,我们改动其中任何一个部分都是比较清楚的。
这个Demo是WPF的MVVM模式的一个登录窗口的完整实例,包含了在MVVM模式下的数据绑定、命令和事件、PasswordBox的绑定、RadioButton等一对多控件的绑定、关闭窗口和打开新窗口和数据验证等内容。
WPF自制TextBox利用Validation验证来实现必填项和焦点的提示特效。 此为专门为MVVM模式的实现。网上要么搜不到真实可用的,要么就是一大堆看不懂的机制绕路太远。我写了个简单明了的。希望可以帮助大家更好地利用...
用MVVM模式做的silverlight自定义日历,可以绑定其他数据,做成进度管理日历或者考勤表
折腾了好久终于可以跟大家分享一下了,一开始的问题是不知道怎么页面加载的时候就自动调用Webservice绑定数据,弄了好久终于知道怎么写了,贴出...Silverlight MVVM例子(通过WebServer 查询数据) 页面加载时绑定数据
silverlight MVVM模式示例。针对MVVM的特性与特点写的一个小例子,适合初学者参考。
实现mvvm模式 Silverlight
Silverlight中使用MVVM.pdf
Silverlight中使用MVVM.docx
MVVM模式实现图片分页显示 (1)数据使用WCF服务加载 (2)定制ListBox数据模板 (3)采用MVVM模式实现分页 注意:在运行前需要修改WCF服务Service1.svc方法GetAllPictureData中的图片文件夹路径,默认是C:\Users\My...
MVVM模式MVVM模式MVVM模式MVVM模式MVVM模式MVVM模式MVVM模式MVVM模式MVVM模式
MVVM模式结合MVVMlight框架的应用 程序=数据结构+算法 面向对象=对象+对象之间关系 1.以数据为中心的开发方式。 1)Model:定义一个数据结构。 关键代码:实现接口INotifyPropertyChanged 2)ViewModel:定义算法...
MVVM模式介绍,里面包含一些简单的例子和代码。