【WPF学习笔记】WPF中使用ValidationRule自定义验证规则

WPF中使用ValidationRule自定义验证规则

本文主要是展示在 WPF 中使用 ValidationRule 自定义验证规则,同时展示两种错误响应方式。一种是通过 Behavior 传递到 ViewModel 中,然后进行错误信息响应;一种是直接在 View 中遍历当前也的所有错误元素,在页面中通过事件统一响应。

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、在前端页面中添加验证

在前端页面中需要进行以下操作:

  1. 添加自定义的 ValidationRule 所有的命名空间;

    xmlns:valRules="clr-namespace:MyValidationRuleDemo.MyValidationRules"
    
  2. 在需要验证的控件上的 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 中默认的效果。效果如下图:

ValidationRule01

3、使用 Behavior 自定义响应效果

上面虽然已经在页面上有了基本的错误响应效果,但是效果过于单一。这里我们在这里使用 Behavior 监听 Validation.Error 事件,并将错误信息传递到 ViewModel 中进行统一进行错误提醒。同时,在 MVMM 架构中将错误信息传递到 ViewModel 中进行统一处理,在有需要的时候也有利于业务逻辑处理。

3.1、实现步骤

进行以上操作需要进行以下步骤:

  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>
    
  2. 通过自定义的 ValidationExceptionBehavior 继承于 Behavior,用于监听 Validation.Error 的错误事件。

    protected override void OnAttached()
    {
        //添加 Validation.Error 事件监听
        this.AssociatedObject.AddHandler(Validation.ErrorEvent, new EventHandler<ValidationErrorEventArgs>(OnValidationError));
    }
    
  3. View 中添加 Behavior;

    <i:Interaction.Behaviors>
        <local:ValidationExceptionBehavior />
    </i:Interaction.Behaviors>
    
  4. 在 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());
        }
    }
    
  5. 在 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());
                                       });
    }
    
  6. 开启 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、效果展示

ValidationRule02

4、直接在页面中进行错误响应

错误响应也可以直接在 View 中通过事件直接处理。但是这样处理就比较麻烦,在获取错误列表时,我们可能需要编写代码,从而在 View 中所有控件中查询有错误的控件。

4.1、单个错误响应

Error 事件是使用冒泡策略的路出事件,我们在 Binding 了 ValidationRule 的控件的父容器上关联处理程序,即可为多个控件处理 Error 事件。

在 View.xaml 中添加如下代码:

<Grid Validation.Error="Grid_Error">
    <!--这里面是具体的页面内容-->
</Grid>

关联的事件处理程序如下:

private void Grid_Error(object sender, ValidationErrorEventArgs e)
{
    if (e.Action == ValidationErrorEventAction.Added)
    {
        MessageBox.Show(e.Error.ErrorContent.ToString());
    }
}

4.2、获取错误列表

循环遍历整个 View 中的元素,并将存在的错误信息收集到一个字符串中,然后点击按钮时将该字符串中的信息展示出来。程序代码如下:

private void Button_Click(object sender, RoutedEventArgs e)
{
    string message;
    if (HasErrors(out message))
    {
        MessageBox.Show(message);
    }
}

private bool HasErrors(out string message)
{
    StringBuilder sb = new StringBuilder();
    GetError(sb, this.grid);
    message = sb.ToString();
    return !string.IsNullOrWhiteSpace(message);
}

private void GetError(StringBuilder sb, DependencyObject obj)
{
    foreach (object child in LogicalTreeHelper.GetChildren(obj))
    {
        StackPanel element = child as StackPanel;
        if (element == null) continue;

        foreach (var ele in element.Children)
        {
            TextBox textBox = ele as TextBox;
            if (textBox == null) continue;
            if (Validation.GetHasError(textBox))
            {
                foreach (ValidationError error in Validation.GetErrors(textBox))
                {
                    sb.Append(error.ErrorContent.ToString() + "\r\n");
                }
                GetError(sb, element);
            }

        }
    }
}
  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
WPF,可以使用ValidationRule自定义验证规则并设置参数。首先,我们需要创建一个继承自ValidationRule自定义验证规则类。在这个类,我们可以重写Validate方法来实现具体的验证逻辑。在方法的参数,我们可以通过传递参数来设置验证规则的值。比如,我们可以在类的构造函数传递一个参数,然后在Validate方法使用该参数进行验证。 例如,我们想要自定义一个验证规则,检查文本框的值是否为一个指定的长度。我们可以创建一个继承自ValidationRule的类,并添加一个长度参数: ``` public class LengthValidationRule : ValidationRule { public int Length { get; set; } public override ValidationResult Validate(object value, CultureInfo cultureInfo) { string input = value.ToString(); if (input.Length == Length) { // 验证通过 return ValidationResult.ValidResult; } else { // 验证失败,返回错误提示信息 return new ValidationResult(false, $"输入值长度应为{Length}位"); } } } ``` 然后,在XAML,我们可以将该验证规则应用于一个绑定的控件,同时设置规则的参数: ``` <TextBox> <TextBox.Text> <Binding Path="SomeProperty"> <Binding.ValidationRules> <local:LengthValidationRule Length="10" /> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> ``` 在上述代码,我们将该验证规则应用于绑定的TextBox控件,并设置Length属性为10,表示输入值需要为10位。当输入的值不满足验证规则时,会在TextBox周围显示验证错误的样式,并显示相应的错误提示信息。 总结来说,通过继承ValidationRule类并设置参数,我们可以在WPF自定义验证规则,并将其应用于需要验证的控件。这样可以轻松实现数据输入的验证逻辑,并为用户提供相应的错误提示。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值