这只是我学习的笔记,大家学习请参考原作者。
参考学习视频:https://www.bilibili.com/video/av40886206/
参照学习博客:https://www.cnblogs.com/wzh2010/p/6285990.html
具体原来太难理解了,只能按照教程把步骤写出来
验证输入效果:
实现步骤:
1,添加资源字典文件
我们新建一个资源字典文件,命名为TextBox.xaml,下面这个是资源字典文件的内容,目标类型是TextBoxBase基础的控件,如TextBox和RichTextBox.
代码比较简单,注意标红的内容,设计一个红底白字的提示框,当源属性触发错误验证的时候,把验证对象集合中的错误内容显示出来。
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Style x:Key="{x:Type TextBoxBase}" TargetType="{x:Type TextBoxBase}" BasedOn="{x:Null}"> <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="Horizontal"> <Border BorderThickness="1" BorderBrush="#FFdc000c" VerticalAlignment="Top"> <Grid> <AdornedElementPlaceholder x:Name="adorner" Margin="-1"/> </Grid> </Border> <Border x:Name="errorBorder" Background="#FFdc000c" Margin="8,0,0,0" Opacity="0" CornerRadius="0" IsHitTestVisible="False" MinHeight="24" > <TextBlock Text="{Binding ElementName=adorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" Foreground="White" Margin="8,2,8,3" TextWrapping="Wrap" VerticalAlignment="Center"/> </Border> </StackPanel> <ControlTemplate.Triggers> <DataTrigger Value="True"> <DataTrigger.Binding> <Binding ElementName="adorner" Path="AdornedElement.IsKeyboardFocused" /> </DataTrigger.Binding> <DataTrigger.EnterActions> <BeginStoryboard x:Name="fadeInStoryboard"> <Storyboard> <DoubleAnimation Duration="00:00:00.15" Storyboard.TargetName="errorBorder" Storyboard.TargetProperty="Opacity" To="1"/> </Storyboard> </BeginStoryboard> </DataTrigger.EnterActions> <DataTrigger.ExitActions> <StopStoryboard BeginStoryboardName="fadeInStoryboard"/> <BeginStoryboard x:Name="fadeOutStoryBoard"> <Storyboard> <DoubleAnimation Duration="00:00:00" Storyboard.TargetName="errorBorder" Storyboard.TargetProperty="Opacity" To="0"/> </Storyboard> </BeginStoryboard> </DataTrigger.ExitActions> </DataTrigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TextBoxBase}"> <Border x:Name="Bd" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true"> <ScrollViewer x:Name="PART_ContentHost" RenderOptions.ClearTypeHint="Enabled" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> </Border> <ControlTemplate.Triggers> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Foreground" Value="{DynamicResource InputTextDisabled}"/> </Trigger> <Trigger Property="IsReadOnly" Value="true"> <Setter Property="Foreground" Value="{DynamicResource InputTextDisabled}"/> </Trigger> <Trigger Property="IsFocused" Value="true"> <Setter TargetName="Bd" Property="BorderBrush" Value="{DynamicResource Accent}" /> </Trigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsReadOnly" Value="False"/> <Condition Property="IsEnabled" Value="True"/> <Condition Property="IsMouseOver" Value="True"/> </MultiTrigger.Conditions> <Setter Property="Background" Value="{DynamicResource InputBackgroundHover}"/> <Setter Property="BorderBrush" Value="{DynamicResource InputBorderHover}"/> <Setter Property="Foreground" Value="{DynamicResource InputTextHover}"/> </MultiTrigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style BasedOn="{StaticResource {x:Type TextBoxBase}}" TargetType="{x:Type TextBox}"> </Style> <Style BasedOn="{StaticResource {x:Type TextBoxBase}}" TargetType="{x:Type RichTextBox}"> </Style> </ResourceDictionary>
2,然后在App.Xaml中全局注册到整个应用中。
3,添加BindDataAnnotationsViewModel类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using GalaSoft.MvvmLight; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using GalaSoft.MvvmLight.Command; using System.Windows; /* * 需要添加引用System.ComponentModel.DataAnnotations.dll */ namespace WPF_MVVMLight.Common { [MetadataType(typeof(BindDataAnnotationsViewModel))] public class BindDataAnnotationsViewModel : ViewModelBase, IDataErrorInfo { public BindDataAnnotationsViewModel() { } #region 属性 /// <summary> /// 表单验证错误集合 /// </summary> private Dictionary<String, String> dataErrors = new Dictionary<String, String>(); private String userName; /// <summary> /// 用户名 /// </summary> [Required] public String UserName { get { return userName; } set { userName = value; } } private String userPhone; /// <summary> /// 用户电话 /// </summary> [Required] [RegularExpression(@"^[-]?[1-9]{8,11}\d*$|^[0]{1}$", ErrorMessage = "用户电话必须为8-11位的数值.")] public String UserPhone { get { return userPhone; } set { userPhone = value; } } private String userEmail; /// <summary> /// 用户邮件 /// </summary> [Required] [StringLength(100, MinimumLength = 2)] [RegularExpression("^\\s*([A-Za-z0-9_-]+(\\.\\w+)*@(\\w+\\.)+\\w{2,5})\\s*$", ErrorMessage = "请填写正确的邮箱地址.")] public String UserEmail { get { return userEmail; } set { userEmail = value; } } #endregion #region 命令 private RelayCommand validFormCommand; /// <summary> /// 验证表单 /// </summary> public RelayCommand ValidFormCommand { get { if (validFormCommand == null) return new RelayCommand(() => ExcuteValidForm()); return validFormCommand; } set { validFormCommand = value; } } /// <summary> /// 验证表单 /// </summary> private void ExcuteValidForm() { if (dataErrors.Count == 0) MessageBox.Show("验证通过!"); else MessageBox.Show("验证失败!"); } #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) { AddDic(dataErrors, vc.MemberName); return string.Join(Environment.NewLine, res.Select(r => r.ErrorMessage).ToArray()); } RemoveDic(dataErrors, vc.MemberName); 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) { if (!dics.ContainsKey(dicKey)) dics.Add(dicKey, ""); } #endregion } }
4,ViewModel
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WPF_MVVMLight.ViewModel { public class AddStudentViewModel:Common.BindDataAnnotationsViewModel { [Required] [StringLength(20,MinimumLength = 2)] public string Name { get; set; } [Range(18,30)] public int Age { get; set; } } }
5,ViewModel注册到Ioc服务器
6,View
DataAnnotations相信很多人很熟悉,可以使用数据批注来自定义用户的模型数据,记得引用 System.ComponentModel.DataAnnotations。
他包含如下几个验证类型:
验证属性 | 说明 |
CustomValidationAttribute | 使用自定义方法进行验证。 |
DataTypeAttribute | 指定特定类型的数据,如电子邮件地址或电话号码。 |
EnumDataTypeAttribute | 确保值存在于枚举中。 |
RangeAttribute | 指定最小和最大约束。 |
RegularExpressionAttribute | 使用正则表达式来确定有效的值。 |
RequiredAttribute | 指定必须提供一个值。 |
StringLengthAttribute | 指定最大和最小字符数。 |
ValidationAttribute | 用作验证属性的基类。 |