WPF中使用IDataErrorInfo进行规则验证

WPF中使用IDataErrorInfo进行数据对象验证

使用 IDataErrorInfo 进行数据对象验证主要有以下步骤:

1、定义一个集合,用于收集错误信息:

private Dictionary<string, string> dataErrors = new Dictionary<string, string>();

2、需要验证的对象的类需要实现 IDataErrorInfo 接口:

  • 具体的数据验证在 this[string columnName] 的 get 访问器中进行。为了防止在处理验证信息时进行大量的条件判断,在这里使用了命名空间 System.ComponentModel.DataAnnotations,将验证条件分离,以 Attribute 的形式关联到每个字段上。
  • 错误信息在这里存储在集合 dataErrors 中,所以需要补充两个方法,用于操作错误dataErrors 。
  • 实现以上处理的 ViewModel 代码如下:
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;

namespace IDataErrorInfoDemo.ViewModel
{
    [MetadataType(typeof(MainViewModel))]
    public class MainViewModel : ViewModelBase, IDataErrorInfo
    {
        public MainViewModel()
        {
            SaveCommand = new RelayCommand(() =>
            {
                if (dataErrors.Count == 0) MessageBox.Show("验证通过!");
                else
                {
                    StringBuilder sb = new StringBuilder();
                    sb.Append("验证失败:\r\n");
                    foreach (var error in dataErrors)
                    {
                        sb.Append(error + "\r\n");
                    }
                    MessageBox.Show(sb.ToString());
                }
            });
        }

        /// <summary>
        /// 页面提交命令
        /// </summary>
        public RelayCommand SaveCommand { get; set; }

        private string userName;
        /// <summary>
        /// 用户名
        /// </summary>
        [Required]
        public string UserName
        {
            get { return userName; }
            set { userName = value; RaisePropertyChanged(); }
        }

        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; }
        }

        /// <summary>
        /// 错误集合
        /// </summary>
        private Dictionary<string, string> dataErrors = new Dictionary<string, string>();

        //IDataErrorInfo的固定实现
        public string Error
        {
            get;
        }

        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 error = string.Join(Environment.NewLine, res.Select(r => r.ErrorMessage).ToArray());
                    AddDic(dataErrors, vc.MemberName, error);
                    return error;
                }
                RemoveDic(dataErrors, vc.MemberName);
                return null;
            }
        }

        /// <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.Remove(dicKey);
                 dics.Add(dicKey, dicValue);
            }
            else
                 dics.Add(dicKey, dicValue);
        }
    }
}

3、在 View 中对需要验证的元素的 Binding 开启属性 :ValidatesOnDataErrors=True

<TextBox
         Text="{Binding UserEmail, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
         Width="200"
         Height="30" />

完整的 View 代码如下:

<Window
    x:Class="IDataErrorInfoDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:IDataErrorInfoDemo"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <StackPanel
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Orientation="Horizontal">
            <Label
                Content="用户名:"
                Margin="0,0,10,0"
                FontSize="20" />
            <TextBox
                Text="{Binding UserName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
                Width="200"
                Height="30" />
        </StackPanel>
        <StackPanel Grid.Row="1"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Orientation="Horizontal">
            <Label
                Content="邮箱:"
                Margin="0,0,10,0"
                FontSize="20" />
            <TextBox
                Text="{Binding UserEmail, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
                Width="200"
                Height="30" />
        </StackPanel>
        <Button Grid.Row="2"
            Content="提交"
            Command="{Binding SaveCommand}"
            Width="200"
            Height="30"
            Margin="0,20,0,0" />
    </Grid>
</Window>

4、实现效果如下:

IDataErrorInfo

posted @ 2021-02-04 23:20  深秋无痕  阅读(46)  评论(0编辑  收藏