WPF--MVVMLight--表单验证

这只是我学习的笔记,大家学习请参考原作者。

参考学习视频:https://www.bilibili.com/video/av40886206/

参照学习博客:https://www.cnblogs.com/wzh2010/p/6285990.html

具体原来太难理解了,只能按照教程把步骤写出来

验证输入效果:

WPF--MVVMLight--表单验证

 

 实现步骤:

1,添加资源字典文件

我们新建一个资源字典文件,命名为TextBox.xaml,下面这个是资源字典文件的内容,目标类型是TextBoxBase基础的控件,如TextBox和RichTextBox.

代码比较简单,注意标红的内容,设计一个红底白字的提示框,当源属性触发错误验证的时候,把验证对象集合中的错误内容显示出来。

WPF--MVVMLight--表单验证

 

 

<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中全局注册到整个应用中。

 

WPF--MVVMLight--表单验证

 

 

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服务器

WPF--MVVMLight--表单验证

 

 

6,View

WPF--MVVMLight--表单验证

 

DataAnnotations相信很多人很熟悉,可以使用数据批注来自定义用户的模型数据,记得引用 System.ComponentModel.DataAnnotations。

他包含如下几个验证类型: 



验证属性 说明 
CustomValidationAttribute 使用自定义方法进行验证。
DataTypeAttribute 指定特定类型的数据,如电子邮件地址或电话号码。
EnumDataTypeAttribute 确保值存在于枚举中。
RangeAttribute 指定最小和最大约束。
RegularExpressionAttribute 使用正则表达式来确定有效的值。
RequiredAttribute 指定必须提供一个值。
StringLengthAttribute 指定最大和最小字符数。
ValidationAttribute 用作验证属性的基类。

 

上一篇:【ECMAScript5】运算符


下一篇:wpf数据绑定之元素、资源、后台绑定