• WPF中如何给TextBox做输入校验
  • 发布于 2个月前
  • 174 热度
    0 评论
  • 怅忘归
  • 0 粉丝 23 篇博客
  •   
引言
在WPF应用程序开发中,数据校验是确保用户输入数据的正确性和完整性的重要一环。之前在做一些参数配置功能时,最是头疼各种参数校验,查阅一些资料后,我总结了数据校验方式有两种:
1. ValidationRule
2. IDataErrorInfo
接下来分别介绍这两种校验方式。

ValidationRule
ValidationRule 是一个抽象类,提供了抽象方法 Validate(), 它是WPF中用于数据验证的一种机制,它可以在用户输入数据之前或之后执行自定义的验证逻辑。可以轻松地实现对数据的格式、范围、逻辑等方面的验证,并在验证失败时提供相应的反馈信息。

备注:ValidationRule主要作用域在前端页面上。

基本用法
首先创建一个 ValidationRule,我这里设定了两个属性 MaxVal、MinVal,然后在 Validate() 方法中判断空、判断大于上限或小于下限,然后在符合条件是,返回 ValidationResult,并给出错误提示:
publicclassIntegerValidationRule : ValidationRule
{
    publicint MaxVal { get; set; }
    publicint MinVal { get; set; }
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        string text = valueasstring;

        if (!int.TryParse(text, outint result))
        {
            returnnew ValidationResult(false, "Text cannot be empty.");
        }

        if (result > MaxVal)
        {
            returnnew ValidationResult(false, "Value out of upper limit range.");
        }

        if (result < MinVal)
        {
            returnnew ValidationResult(false, "Value out of lower limit range.");
        }

        return ValidationResult.ValidResult;
    }
}
接下来创建有个测试使用的 ViewModel:
publicclassTestViewModel : INotifyPropertyChanged
{
    private TestViewModel() { }
    publicstatic TestViewModel Instance { get; } = new TestViewModel();
    publicevent PropertyChangedEventHandler? PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    privateint testField1;
    /// <summary>
    /// 堆代码 duidaima.com
    /// 测试属性1
    /// </summary>
    publicint TestField1
    {
        get => testField1;
        set
        {
            testField1 = value;
            OnPropertyChanged(nameof(TestField1));
        }
    }

    privateint testField2;
    /// <summary>
    /// 测试属性2
    /// </summary>
    publicint TestField2
    {
        get => testField2;
        set
        {
            testField2 = value;
            OnPropertyChanged(nameof(TestField2));
        }
    }
}
在测试之前,我们可以先看一下 Binding 的方法列表:

可以看到 「ValidationRules 是 Binding 下的集合,这意味着 ValidationRule 是在 Binding 下使用且可以执行多个校验规则。校验时按照顺序依次校验。」

接下来我们创建一个WPF应用程序,在界面添加 TextBox,命名为”textbox1“,将文本绑定在 TestViewModel 的 TestField1。且为Validation.ErrorTemplate 绑定一个模板,这里绑定了一个红色的感叹号。然后为 TextBox 设置触发器,当 Validation.HasError为 true时,将 ToolTip 绑定校验失败的错误提示。

代码如下:
<Window
    x:Class="WpfApp4.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:local="clr-namespace:WpfApp4"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="900"
    Height="450"
    mc:Ignorable="d">
    <Window.Resources>
        <ControlTemplate x:Key="ValidationTemplate">
            <DockPanel>
                <TextBlock
                    Margin="-10,0,0,0"
                    VerticalAlignment="Center"
                    FontSize="22"
                    Foreground="Red"
                    Text="!" />

            </DockPanel>
        </ControlTemplate>

        <Style TargetType="TextBox">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="true">
                    <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*" />
            <ColumnDefinition Width="1*" />
        </Grid.ColumnDefinitions>
        <StackPanel Grid.Column="0">
            <TextBlock
                HorizontalAlignment="Center"
                FontSize="18"
                FontWeight="Bold"
                Text="Validation Demo" />
            <TextBox
                Name="textBox1"
                Height="30"
                Margin="10"
                FontSize="22"
                Validation.ErrorTemplate="{StaticResource ValidationTemplate}">
                <TextBox.Text>
                    <Binding Path="TestField1" UpdateSourceTrigger="PropertyChanged">
                        <Binding.ValidationRules>
                            <local:IntegerValidationRule
                                MaxVal="999"
                                MinVal="5" />
                        </Binding.ValidationRules>
                    </Binding>
                </TextBox.Text>
            </TextBox>

        </StackPanel>
    </Grid>
</Window>
最后在窗体后台绑定 ViewModel:
public MainWindow()
{
    InitializeComponent();
    this.DataContext =  TestViewModel.Instance;
}
测试
1.为空时,出现红色叹号,ToolTip 提示 "Text cannot be empty."

2.小于下限时,出现红色叹号,ToolTip 提示 "Value out of lower limit range."

3.大于上限时,出现红色叹号,ToolTip 提示 "Value out of upper limit range."



IDataErrorInfo
IDataErrorInfo 是一个接口,Viewmodel 实现接口用于在后台,提供数据验证和错误信息。IDataErrorInfo 主要作用域为后台 ViewModel该接口包含两个成员:Error 和 this[string columnName]。这两个成员允许你在数据绑定时提供验证错误信息。

基本用法
接下来,在程序里添加 TextBox,命名为”textbox2“,并添加一个 TextBlock 绑定 Error 展示在界面。
<StackPanel Grid.Column="1">
    <TextBlock
        HorizontalAlignment="Center"
        FontSize="18"
        FontWeight="Bold"
        Text="IDataErrorInfo Demo" />
    <TextBox
        Name="textBox2"
        Margin="10"
        VerticalAlignment="Center"
        FontSize="22"
        Text="{Binding TestField2, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
     <TextBlock
         HorizontalAlignment="Center"
         FontSize="18"
         FontWeight="Bold"
         Foreground="Red"
         Text="{Binding Error, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
后台 TestViweModel 实现 IDataErrorInfo,依旧是判断上限值和下限值,此处不判断空,是因为后台 TestField2 类型是Int,为空时不会赋值,代码如下:
publicclassTestViewModel : INotifyPropertyChanged, IDataErrorInfo
{
    //省略上文已有代码..。
    //堆代码 duidaima.com
    privatestring error;
    publicstring Error
    {
        get => error;
        set
        {
            error = value; OnPropertyChanged(nameof(Error));
        }
    }
    publicstringthis[string columnName]
    {
        get
        {
            switch (columnName)
            {
                case nameof(TestField2):
                    return CheckTestFild2();
                default:
                    returnnull;
            }
        }
    }

    publicint MaxVal = 999;
    publicint MinVal = 5;

    private string CheckTestFild2()
    {
        if (TestField2 > MaxVal)
        {
            Error = "Value out of upper limit range in viewmodel.";
        }
        elseif (TestField2 < MinVal)
        {
            Error = "Value out of lower limit range  in viewmodel.";
        }
        else
        {
            Error = string.Empty;
        }
        
        return Error;
    }
}
测试
1.小于下限时,出现红色文字提示,ToolTip 提示 "Value out of lower limit range in viewmodel."

2.大于上限时,出现红色文字提示,ToolTip 提示 "Value out of upper limit range in viewmodel."



小结
以上两种数据校验(IDataErrorInfo、ValidationRule)的方式,均可以实现自定义数据校验,例如对数据的格式、范围、逻辑等方面的验证,并在验证失败时提供相应的反馈信息。

ValidationRule适用于在界面做数据校验,且可以定义多个校验规则。
IDataErrorInfo适用于在ViewModel做数据校验,可以做一些无法在前端页面做的事情,比如出现异常值是还原为默认值。

所以两者既可以单独使用,也可以组合使用,即使使用MVVM模式,依旧能够优雅的做数据校验。
用户评论