WPF --- TextBox的输入校验

引言

在WPF应用程序开发中,数据校验是确保用户输入数据的正确性和完整性的重要一环。

之前在做一些参数配置功能时,最是头疼各种参数校验,查阅一些资料后,我总结了数据校验方式有两种:

  • ValidationRule
  • IDataErrorInfo

接下来分别介绍这两种校验方式。

ValidationRule

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

ValidationRule主要作用域在前端页面上

基本用法

首先创建一个 ValidationRule,我这里设定了两个属性 MaxValMinVal,然后在 Validate() 方法中判断空、判断大于上限或小于下限,然后在符合条件是,返回 ValidationResult,并给出错误提示:

csharp 复制代码
public class IntegerValidationRule : ValidationRule
{
    public int MaxVal { get; set; }
    public int MinVal { get; set; }

    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        string text = value as string;

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

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

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

        return ValidationResult.ValidResult;
    }
}

接下来创建有个测试使用的 ViewModel:

csharp 复制代码
public class TestViewModel : INotifyPropertyChanged
{
    private TestViewModel() { }

    public static TestViewModel Instance { get; } = new TestViewModel();

    public event PropertyChangedEventHandler? PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private int testField1;
    /// <summary>
    /// 测试属性1
    /// </summary>
    public int TestField1
    {
        get => testField1;
        set
        {
            testField1 = value;
            OnPropertyChanged(nameof(TestField1));
        }
    }

    private int testField2;
    /// <summary>
    /// 测试属性2
    /// </summary>
    public int TestField2
    {
        get => testField2;
        set
        {
            testField2 = value;
            OnPropertyChanged(nameof(TestField2));
        }
    }
}

在测试之前,我们可以先看一下 Binding 的方法列表:

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

接下来我们创建一个WPF应用程序,在界面添加 TextBox,命名为"textbox1",将文本绑定在 TestViewModelTestField1

且为Validation.ErrorTemplate 绑定一个模板,这里绑定了一个红色的感叹号。

然后为 TextBox 设置触发器,当 Validation.HasErrortrue时,将 ToolTip 绑定校验失败的错误提示。

代码如下:

xml 复制代码
<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:

csharp 复制代码
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

该接口包含两个成员:Errorthis[string columnName]。这两个成员允许你在数据绑定时提供验证错误信息。

基本用法

接下来,在程序里添加 TextBox,命名为"textbox2",并添加一个 TextBlock 绑定 Error 展示在界面。

xml 复制代码
<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,为空时不会赋值,代码如下:

csharp 复制代码
public class TestViewModel : INotifyPropertyChanged, IDataErrorInfo
{
    //省略上文已有代码..。
    
    private string error;
    public string Error
    {
        get => error;
        set
        {
            error = value; OnPropertyChanged(nameof(Error));
        }
    }
    public string this[string columnName]
    {
        get
        {
            switch (columnName)
            {
                case nameof(TestField2):
                    return CheckTestFild2();
                default:
                    return null;
            }
        }
    }

    public int MaxVal = 999;
    public int MinVal = 5;

    private string CheckTestFild2()
    {
        if (TestField2 > MaxVal)
        {
            Error = "Value out of upper limit range in viewmodel.";
        }
        else if (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."

小结

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

ValidationRule适用于在界面做数据校验,且可以定义多个校验规则。

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

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

相关推荐
5008416 小时前
鸿蒙 Flutter 权限管理进阶:动态权限、权限组、兼容处理与用户引导
flutter·华为·架构·wpf·开源鸿蒙
5008417 小时前
鸿蒙 Flutter 蓝牙与 IoT 开发进阶:BLE 设备连接、数据交互与设备管理
flutter·华为·electron·wpf·开源鸿蒙
Macbethad18 小时前
工业设备系统管理程序技术方案
大数据·wpf
5008420 小时前
鸿蒙 Flutter 混合栈开发:与 React Native/ArkTS 页面无缝集成(2025 爆火方案)
flutter·华为·electron·wpf·开源鸿蒙
拾七片晚星2 天前
MateChat工作流引擎实战:复杂任务自动化编排与异常处理
wpf·devui·matechat
Aevget2 天前
界面控件开发包DevExpress v25.1.7更新上线——修复一些小bug
c#·wpf·winform·devexpress·ui开发·用户界面
_oP_i2 天前
winform与wpf的对比
wpf
她说彩礼65万2 天前
WPF Converter转换器
wpf
她说彩礼65万2 天前
C# Thread和Task的区别
wpf
张人玉2 天前
C#编写西门子S7PLC通信的相关知识点
microsoft·c#·wpf·plc·西门子s7通信