WPF--MVVMLight--表单验证
这只是我学习的笔记,大家学习请参考原作者。
参考学习视频: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 | 用作验证属性的基类。 |

浙公网安备 33010602011771号