【WPF学习笔记】WPF中使用ValidationRule自定义验证规则
WPF中使用ValidationRule自定义验证规则
本文主要是展示在 WPF 中使用 ValidationRule 自定义验证规则,然后通过 Behavior 传递到 ViewModel 中,在 ViewModel 中对错误信息统一响应。
1、自定义验证规则类
这里自定义两个验证规则类,分别用于验证 “用户名”输入不可为空、“邮箱”输入值需满足格式要求。
两个类需要继承 ValidationRule 类。ValidationRule 是抽象类,需要具体实现 Validate 方法。代码如下:
NotEmptyValidationRule.cs
using System.Globalization;
using System.Windows.Controls;
namespace MyValidationRuleDemo.MyValidationRules
{
    public class NotEmptyValidationRule : ValidationRule
    {
        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            return string.IsNullOrWhiteSpace((value ?? "").ToString()) ?
                new ValidationResult(false, "不能为空") : new ValidationResult(true, null);
        }
    }
}
EmailValidationRule.cs
using System.Globalization;
using System.Text.RegularExpressions;
using System.Windows.Controls;
namespace MyValidationRuleDemo.MyValidationRules
{
    public class EmailValidationRule : ValidationRule
    {
        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            Regex emailRegex = new Regex("^\\s*([A-Za-z0-9_-]+(\\.\\w+)*@(\\w+\\.)+\\w{2,5})\\s*$");
            string str = (value ?? "").ToString();
            if (!string.IsNullOrWhiteSpace(str))
            {
                if (!emailRegex.IsMatch(str))
                {
                    return new ValidationResult(false, "邮箱地址错误!");
                }
            }
            return new ValidationResult(true, null);
        }
    }
}
2、在前端页面中添加验证
在前端页面中需要进行以下操作:
- 
添加自定义的 ValidationRule 所有的命名空间; xmlns:valRules="clr-namespace:MyValidationRuleDemo.MyValidationRules"
- 
在需要验证的控件上的 Binding 上对应的自定义验证规则类; <Binding.ValidationRules> <valRules:EmailValidationRule /> </Binding.ValidationRules>
具体代码如下:
<Window
    x:Class="MyValidationRuleDemo.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:MyValidationRuleDemo"
    xmlns:valRules="clr-namespace:MyValidationRuleDemo.MyValidationRules"
    Title="MainWindow"
    Width="800"
    Height="400"
    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 Width="200" Height="30">
                <TextBox.Text>
                    <Binding
                        Path="UserName"
                        UpdateSourceTrigger="PropertyChanged">
                        <Binding.ValidationRules>
                            <valRules:NotEmptyValidationRule />
                        </Binding.ValidationRules>
                    </Binding>
                </TextBox.Text>
            </TextBox>
        </StackPanel>
        <StackPanel Grid.Row="1"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Orientation="Horizontal">
            <Label
                Content="邮箱:"
                Margin="0,0,10,0"
                FontSize="20" />
            <TextBox Width="200" Height="30">
                <TextBox.Text>
                    <Binding
                        Path="UserEmail"
                        UpdateSourceTrigger="PropertyChanged">
                        <Binding.ValidationRules>
                            <valRules:EmailValidationRule />
                        </Binding.ValidationRules>
                    </Binding>
                </TextBox.Text>
            </TextBox>
        </StackPanel>
        <Button Grid.Row="2"
            Content="提交"
            Width="200"
            Height="30"
            Margin="0,20,0,0" />
    </Grid>
</Window>
前端页面绑定的验证参数具体如下:
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
namespace MyValidationRuleDemo.ViewModel
{
    public class MainViewModel : ViewModelBase
    {
        public MainViewModel()
        {
        }
        private string userName;
        /// <summary>
        /// 用户名
        /// </summary>
        public string UserName
        {
            get { return userName; }
            set { userName = value; RaisePropertyChanged(); }
        }
        private string userEmail;
        /// <summary>
        /// 用户邮件
        /// </summary>
        public string UserEmail
        {
            get { return userEmail; }
            set { userEmail = value; RaisePropertyChanged(); }
        }
    }
}
此时,自定义的验证规则已经生效。当页面输入不符合规则时,会默认的红框进行标记。这是 WPF 中默认的效果。效果如下图:

3、使用 Behavior 自定义响应效果
上面虽然已经在页面上有了基本的错误响应效果,但是效果过于单一。这里我们在这里使用 Behavior 监听 Validation.Error 事件,并将错误信息传递到 ViewModel 中进行统一进行错误提醒。同时,在 MVMM 架构中将错误信息传递到 ViewModel 中进行统一处理,在有需要的时候也有利于业务逻辑处理。
3.1、实现步骤
进行以上操作需要进行以下步骤:
- 
开启验证错误的通知属性 NotifyOnValidationError="True" 。这样就可以产生 Validation.Error 事件。 <TextBox Width="200" Height="30"> <TextBox.Text> <Binding Path="UserEmail" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <valRules:EmailValidationRule /> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox>
- 
通过自定义的 ValidationExceptionBehavior 继承于 Behavior,用于监听 Validation.Error 的错误事件。 protected override void OnAttached() { //添加 Validation.Error 事件监听 this.AssociatedObject.AddHandler(Validation.ErrorEvent, new EventHandler<ValidationErrorEventArgs>(OnValidationError)); }
- 
View 中添加 Behavior; <i:Interaction.Behaviors> <local:ValidationExceptionBehavior /> </i:Interaction.Behaviors>
- 
在 ValidationExceptionBehavior 中通过 AssociatedObject 的DataContext 获取到关联当前View的ViewModel。并将错误提示统一收集到 ViewModel 的 ErrorList 。 private void OnValidationError(Object sender, ValidationErrorEventArgs e) { MainViewModel mainModel = null; if (AssociatedObject.DataContext is MainViewModel) { mainModel = this.AssociatedObject.DataContext as MainViewModel; } if (mainModel == null) return; //OriginalSource 触发事件的元素 var element = e.OriginalSource as UIElement; if (element == null) return; //ValidationErrorEventAction.Added 表示新产生的行为 if (e.Action == ValidationErrorEventAction.Added) { mainModel.ErrorList.Add(e.Error.ErrorContent.ToString()); } else if (e.Action == ValidationErrorEventAction.Removed) //ValidationErrorEventAction.Removed 该行为被移除,即代表验证通过 { mainModel.ErrorList.Remove(e.Error.ErrorContent.ToString()); } }
- 
在 View 中按钮绑定的 Command 中统一处理 ErrorList; public RelayCommand SaveCommand { get; set; } public MainViewModel() { SaveCommand = new RelayCommand(() => { StringBuilder sb = new StringBuilder(); foreach (var error in ErrorList) { sb.Append(error + "\r\n"); } MessageBox.Show(sb.ToString()); }); }
- 
开启 ValidationRule 的属性 ValidatesOnTargetUpdated="True",否则在加载页面后,文本框中未输入值则不会进行验证。 <Binding.ValidationRules> <valRules:EmailValidationRule ValidatesOnTargetUpdated="True" /> </Binding.ValidationRules>
3.2、具体代码
完整代码如下:
ValidationExceptionBehavior.cs
using MyValidationRuleDemo.ViewModel;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
namespace MyValidationRuleDemo
{
    public class ValidationExceptionBehavior : Behavior<FrameworkElement>
    {
        protected override void OnAttached()
        {
            //添加 Validation.Error 事件监听
            this.AssociatedObject.AddHandler(Validation.ErrorEvent, new EventHandler<ValidationErrorEventArgs>(OnValidationError));
        }
        private void OnValidationError(Object sender, ValidationErrorEventArgs e)
        {
            MainViewModel mainModel = null;
            if (AssociatedObject.DataContext is MainViewModel)
            {
                mainModel = this.AssociatedObject.DataContext as MainViewModel;
            }
            if (mainModel == null) return;
            //OriginalSource 触发事件的元素
            var element = e.OriginalSource as UIElement;
            if (element == null) return;
            //ValidationErrorEventAction.Added  表示新产生的行为
            if (e.Action == ValidationErrorEventAction.Added)
            {
                mainModel.ErrorList.Add(e.Error.ErrorContent.ToString());
            }
            else if (e.Action == ValidationErrorEventAction.Removed) //ValidationErrorEventAction.Removed  该行为被移除,即代表验证通过
            {
                mainModel.ErrorList.Remove(e.Error.ErrorContent.ToString());
            }
        }
        protected override void OnDetaching()
        {
            //移除 Validation.Error 事件监听
            this.AssociatedObject.RemoveHandler(Validation.ErrorEvent, new EventHandler<ValidationErrorEventArgs>(OnValidationError));
        }
    }
}
MainView.xaml
<Window
    x:Class="MyValidationRuleDemo.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:MyValidationRuleDemo"
    xmlns:valRules="clr-namespace:MyValidationRuleDemo.MyValidationRules"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    Title="MainWindow"
    Width="800"
    Height="400"
    mc:Ignorable="d">
    <i:Interaction.Behaviors>
        <local:ValidationExceptionBehavior />
    </i:Interaction.Behaviors>
    <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 Width="200" Height="30">
                <TextBox.Text>
                    <Binding
                        Path="UserName"
                        NotifyOnValidationError="True"
                        UpdateSourceTrigger="PropertyChanged">
                        <Binding.ValidationRules>
                            <valRules:NotEmptyValidationRule ValidatesOnTargetUpdated="True" />
                        </Binding.ValidationRules>
                    </Binding>
                </TextBox.Text>
            </TextBox>
        </StackPanel>
        <StackPanel Grid.Row="1"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Orientation="Horizontal">
            <Label
                Content="邮箱:"
                Margin="0,0,10,0"
                FontSize="20" />
            <TextBox Width="200" Height="30">
                <TextBox.Text>
                    <Binding
                        Path="UserEmail"
                        NotifyOnValidationError="True"
                        UpdateSourceTrigger="PropertyChanged">
                        <Binding.ValidationRules>
                            <valRules:EmailValidationRule ValidatesOnTargetUpdated="True" />
                        </Binding.ValidationRules>
                    </Binding>
                </TextBox.Text>
            </TextBox>
        </StackPanel>
        <Button Grid.Row="2"
            Content="提交"
            Command="{Binding SaveCommand}"
            Width="200"
            Height="30"
            Margin="0,20,0,0" />
    </Grid>
</Window>
MainViewModel.cs
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System.Collections.ObjectModel;
using System.Text;
using System.Windows;
namespace MyValidationRuleDemo.ViewModel
{
    public class MainViewModel : ViewModelBase
    {
        public MainViewModel()
        {
            SaveCommand = new RelayCommand(() =>
            {
                StringBuilder sb = new StringBuilder();
                foreach (var error in ErrorList)
                {
                    sb.Append(error + "\r\n");
                }
                MessageBox.Show(sb.ToString());
            });
        }
        public RelayCommand SaveCommand { get; set; }
        private string userName;
        /// <summary>
        /// 用户名
        /// </summary>
        public string UserName
        {
            get { return userName; }
            set { userName = value; RaisePropertyChanged(); }
        }
        private string userEmail;
        /// <summary>
        /// 用户邮件
        /// </summary>
        public string UserEmail
        {
            get { return userEmail; }
            set { userEmail = value; RaisePropertyChanged(); }
        }
        private ObservableCollection<string> errorList = new ObservableCollection<string>();
        /// <summary>
        /// 错误提示
        /// </summary>
        public ObservableCollection<string> ErrorList
        {
            get { return errorList; }
            set { errorList = value; RaisePropertyChanged(); }
        }
    }
}
3.3、效果展示

 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号