WPF开发随笔收录-DataAnnotations实现数据校验(MVVM架构下)

  • A+
所属分类:.NET技术
摘要

在自己的项目中挺多地方需要涉及到数据验证的,初期的实现方式都是通过点击确定后再逐个验证数据是否符合要求,但这种方式会让后台代码变得很多很乱。于是就开始在网上需求好的解决方式,刚好看到了一个大佬的博客写了关于数据验证的博客,也成功将那个方法用在项目中了,今天就来这里分享一下。博客原文:https://www.cnblogs.com/wzh2010/p/6518834.html


一、前言

在自己的项目中挺多地方需要涉及到数据验证的,初期的实现方式都是通过点击确定后再逐个验证数据是否符合要求,但这种方式会让后台代码变得很多很乱。于是就开始在网上需求好的解决方式,刚好看到了一个大佬的博客写了关于数据验证的博客,也成功将那个方法用在项目中了,今天就来这里分享一下。博客原文:https://www.cnblogs.com/wzh2010/p/6518834.html

二、正文

1、这里写一个简单的例子来作为参考,首先新建个项目,按照常规MVVM构建好项目,如下图。然后添加需要用到的通知基类和命令基类

WPF开发随笔收录-DataAnnotations实现数据校验(MVVM架构下)

 

 2、然后就是添加一个验证的基类ValidateModelBase,后面需要实现验证的类直接继承这个类即可,这个代码是直接搬大佬的

public class ValidateModelBase : NotifyBase, IDataErrorInfo {     public ValidateModelBase()     {      }      #region 属性      /// <summary>     /// 表当验证错误集合     /// </summary>     public Dictionary<string, string> dataErrors = new Dictionary<string, string>();      /// <summary>     /// 是否验证通过     /// </summary>     public bool IsValidated     {         get         {             if (dataErrors != null && dataErrors.Count > 0)             {                 return false;             }             return true;         }     }     #endregion      public string this[string columnName]     {         get         {             ValidationContext vc = new ValidationContext(this, null, null);             vc.MemberName = columnName;             var res = new List<ValidationResult>();             var result = Validator.TryValidateProperty(this.GetType().GetProperty(columnName).GetValue(this, null), vc, res);             if (res.Count > 0)             {                 string errorInfo = string.Join(Environment.NewLine, res.Select(r => r.ErrorMessage).ToArray());                 AddDic(dataErrors, columnName, errorInfo);                 return errorInfo;             }             RemoveDic(dataErrors, columnName);             return null;         }     }      public string Error     {         get         {             return null;         }     }       #region 附属方法     /// <summary>     /// 移除字典     /// </summary>     /// <param name="dics"></param>     /// <param name="dicKey"></param>     private void RemoveDic(Dictionary<string, string> dics, string dicKey)     {         dics.Remove(dicKey);     }      /// <summary>     /// 添加字典     /// </summary>     /// <param name="dics"></param>     /// <param name="dicKey"></param>     private void AddDic(Dictionary<string, string> dics, string dicKey, string dicValue)     {         if (!dics.ContainsKey(dicKey)) dics.Add(dicKey, dicValue);     }     #endregion }

3、接着我们创建一个类,并添加需要验证的字段

public class UserModel : ValidateModelBase {     private string userName;     [Required(ErrorMessage = "用户名不可为空")]     public string UserName     {         get { return userName; }         set { userName = value; DoNotify(); }     }      private string userAge;     [Required(ErrorMessage = "年龄不可为空")]     [Range(0, 100, ErrorMessage = "年龄范围为0~100")]     public string UserAge     {         get { return userAge; }         set { userAge = value; DoNotify(); }     }      private bool isFormValid;      public bool IsFormValid     {         get { return isFormValid; }         set { isFormValid = value; DoNotify(); }     } }

4、重写一下TextBox的Validation.ErrorTemplate模板

<Style     x:Key="{x:Type TextBoxBase}"     BasedOn="{x:Null}"     TargetType="{x:Type TextBoxBase}">     <Setter Property="BorderThickness" Value="1" />     <Setter Property="Padding" Value="2,1,1,1" />     <Setter Property="AllowDrop" Value="true" />     <Setter Property="FocusVisualStyle" Value="{x:Null}" />     <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst" />     <Setter Property="Stylus.IsFlicksEnabled" Value="False" />     <Setter Property="SelectionBrush" Value="{DynamicResource Accent}" />     <Setter Property="Validation.ErrorTemplate">         <Setter.Value>             <ControlTemplate>                 <StackPanel Orientation="Vertical">                     <Border                         x:Name="adornerborder"                         BorderThickness="1">                         <Grid>                             <AdornedElementPlaceholder x:Name="adorner" Margin="-1" />                         </Grid>                     </Border>                     <Border                         x:Name="errorBorder"                         Background="Transparent"                         CornerRadius="0"                         IsHitTestVisible="False"                         Opacity="0">                         <TextBlock                             VerticalAlignment="Center"                             Foreground="Red"                             Text="{Binding ElementName=adorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"/>                     </Border>                 </StackPanel>                  <ControlTemplate.Triggers>                     <DataTrigger Value="True">                         <DataTrigger.Binding>                             <Binding ElementName="adorner" Path="AdornedElement.Tag" />                         </DataTrigger.Binding>                         <DataTrigger.EnterActions>                             <BeginStoryboard x:Name="fadeInStoryboard1">                                 <Storyboard>                                     <DoubleAnimation                                         Storyboard.TargetName="errorBorder"                                         Storyboard.TargetProperty="Opacity"                                         To="1"                                         Duration="00:00:00.15" />                                 </Storyboard>                             </BeginStoryboard>                         </DataTrigger.EnterActions>                         <DataTrigger.Setters>                             <Setter TargetName="adornerborder" Property="BorderBrush" Value="#FFdc000c" />                         </DataTrigger.Setters>                     </DataTrigger>                      <DataTrigger Value="True">                         <DataTrigger.Binding>                             <Binding ElementName="adorner" Path="AdornedElement.IsKeyboardFocused" />                         </DataTrigger.Binding>                         <DataTrigger.EnterActions>                             <BeginStoryboard x:Name="fadeInStoryboard">                                 <Storyboard>                                     <DoubleAnimation                                         Storyboard.TargetName="errorBorder"                                         Storyboard.TargetProperty="Opacity"                                         To="1"                                         Duration="00:00:00.15" />                                 </Storyboard>                             </BeginStoryboard>                         </DataTrigger.EnterActions>                         <DataTrigger.Setters>                             <Setter TargetName="adornerborder" Property="BorderBrush" Value="#FFdc000c" />                         </DataTrigger.Setters>                     </DataTrigger>                 </ControlTemplate.Triggers>             </ControlTemplate>         </Setter.Value>     </Setter> </Style>

5、接着在主窗口添加两个TextBox,然后绑定上对应的字段,记得要加上这个ValidatesOnDataErrors=True,不然无效

<Grid>     <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">         <StackPanel Margin="0,10" Orientation="Horizontal">             <Label                 Width="80"                 Content="用户姓名:" />             <TextBox                 Width="150"                 Tag="{Binding UserModel.IsFormValid, UpdateSourceTrigger=PropertyChanged}"                 Text="{Binding UserModel.UserName, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />         </StackPanel>         <StackPanel Margin="0,10" Orientation="Horizontal">             <Label                 Width="80"                 Content="用户年龄:" />             <TextBox                 Width="150"                 Tag="{Binding UserModel.IsFormValid, UpdateSourceTrigger=PropertyChanged}"                 Text="{Binding UserModel.UserAge, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />         </StackPanel>          <Button             Margin="0,10,0,0"             Command="{Binding SubmitCommand}"             Content="提交" />     </StackPanel> </Grid>

6、然后就是ViewModel的代码

public class MainWindowViewModel : NotifyBase {     private UserModel userModel;      public UserModel UserModel     {         get { return userModel; }         set { userModel = value; DoNotify(); }     }      public CommandBase SubmitCommand { get; set; } = new CommandBase();      public MainWindowViewModel()     {         UserModel = new UserModel();          SubmitCommand.DoExecute = new Action<object>(DoSumit);         SubmitCommand.DoCanExecute = new Func<object, bool>((o) => { return true; });     }      private void DoSumit(object obj)     {         if (UserModel.IsValidated) MessageBox.Show("验证通过!");         else         {             UserModel.IsFormValid = true;             var dataErrors = UserModel.dataErrors;             MessageBox.Show("验证失败");         }     } }

7、到这里功能的实现就基本完成了,不擅长讲解原理,不太懂得可以研究研究官方文档获取其他大佬的文章,实现效果如下:

WPF开发随笔收录-DataAnnotations实现数据校验(MVVM架构下)