WPF输入验证(ValidationRule)

验证原理

当数据在页面上被用户输入时,数据的流向是页面->验证->viewmodel,也就是说如果验证不通过,数据不会到viewmodel中

使用ValidationRule方式

**实现效果:**当规则验证为不通过时,页面上输入非法,框会变红,并且显示错误原因

1.创建类,继承ValidationRule

2.重载Validate方法

cs 复制代码
internal class RestrictNegativeValues : ValidationRule
{
   //方法的重载
   // value 就是 TextBox 里用户输入的内容。
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {

        // 因为 TextBox 的 Text 属性是字符串,所以这里把它强转为 string 类型
        string str = value as string;

        // 检查字符串是否为空、null 或者全是空格
        if (string.IsNullOrWhiteSpace(str))
        {
            // 如果为空,返回一个"验证失败"的结果
            // false代表失败,后面是提示文字
            return new ValidationResult(false, "不能为空");
        }

        // --- 第三步:检查是否为数字 ---

        double result; // 定义一个变量用来存放转换后的数字

        // double.TryParse 尝试将字符串转换为数字。
        // 如果转换成功(比如输入"123"),返回 true;
        // 如果转换失败(比如输入"abc"),返回 false。
        if (!double.TryParse(str, out result))
        {
            // 如果不是数字,返回失败结果
            return new ValidationResult(false, "必须是数字");
        }

        // --- 第四步:检查是否小于 0 ---

        // 此时 result 已经是合法的数字了,我们可以直接比较大小
        if (result < 0)
        {
            // 如果是负数,返回失败结果
            return new ValidationResult(false, "不能为负数");
        }

        // --- 第五步:验证通过 ---

        // 如果代码运行到了这里,说明既不是空,也是数字,也不是负数
        // 返回 ValidationResult.ValidResult 表示一切正常,允许数据通过
        return ValidationResult.ValidResult;
    }
}

3.xaml页面引用命名空间+绑定

  • 要实现验证,在text属性中除了绑定viewmodel中属性还要绑定验证规则,也就是1,2继承ValidationRule的类
  • 验证规则不止可以绑定一条
  • (Validation.Errors)[0]是验证规则生成的错误列表的第一条,只有没有通过的验证规则的才会进入这个列表,并且列表中错误的顺序和xaml中规则的顺序相同,但是不一一对应,也就是正确的不进入
XML 复制代码
 <TextBox
     Name="AngleFactorTextBox"
     >
     <TextBox.Text>
         <Binding Mode="TwoWay" Path="AngleFactor">
             <Binding.ValidationRules>
                 <Validation:RestrictNegativeValues />
             </Binding.ValidationRules>
         </Binding>
     </TextBox.Text>
 </TextBox>
 <TextBlock
     Margin="5,0,0,0"
     VerticalAlignment="Center"
     FontSize="12"
     Foreground="Red">
     <!--  绑定逻辑:绑定到上面 TextBox 的错误信息  -->
     <TextBlock.Text>
         <Binding
             ElementName="AngleFactorTextBox"
             Mode="OneWay"
             Path="(Validation.Errors)[0].ErrorContent" />
     </TextBlock.Text>
 </TextBlock>

使用模板设置统一验证

使用场景:多个输入框,验证规则相同

步骤一.资源字典中设置

XML 复制代码
//实际上是把"输入框"和"错误提示"打包成了一个临时的组合控件
<ControlTemplate x:Key="ValidationTextBoxTemplate">
    <DockPanel>
<!--  原来的 TextBox (用 AdornedElementPlaceholder 占位)  -->
        <AdornedElementPlaceholder DockPanel.Dock="Top"/>
        <!--  错误提示文字 (TextBlock)  -->
        <TextBlock
            VerticalAlignment="Center"
            DockPanel.Dock="Bottom"
            FontSize="12"
            Foreground="Red"
            Text="{Binding [0].ErrorContent}"
            Visibility="Visible" />    
    </DockPanel>
</ControlTemplate>

这里Text中内容,不需要写(Validation.Errors)不需要指定elementname?

1. 关于 ElementName

解释: "那一个控件发生变化,触发器触发,就直接知道是哪一个控件,无需 ElementName。"

  • 原理ErrorTemplate 是依附于控件的"寄生"层(Adorner)。
  • 过程
    1. WPF 看到 Trigger 触发(HasError=True)。
    2. WPF 会在当前这个 TextBox 的上方创建一个"覆盖层"(Adorner)。
    3. 既然是这个 TextBox 召唤出来的覆盖层,覆盖层里的内容自然就是为这个 TextBox 服务的。
    4. AdornedElementPlaceholder 这个标签的意思就是:"把那个召唤我的 TextBox 放在这里"。
  • 结论 :不需要 ElementName,因为它们是"母子关系",孩子天然知道母亲是谁。

2. 关于 (Validation.Errors)

你的解释: "模板上下文被强制指定为 Validation.Errors。"
点评: 完全正确。

  • 原理 :这是 WPF 的 Validation.ErrorTemplate 特有的"特殊待遇"。
  • 过程
    • 普通控件DataContext 是你的 ViewModel。你想看错误,得写长路径去"找"错误。
    • 错误模板 :WPF 在渲染模板时,做了一个**"偷梁换柱"** 的操作,它把模板的 DataContext 强行切换成了 Validation.Errors 集合。
  • 结论 :因为"人"已经站在了"错误列表"里,所以不需要写 Path=(Validation.Errors),直接写 [0](取第一个)即可。

步骤二.为需要设置模板的Textbox设置统一样式

XML 复制代码
<Style x:Key="SensorValueStyle" TargetType="TextBox">
    <!--  默认不显示错误模板,{x:null}代表空引用  -->
    <Setter Property="Validation.ErrorTemplate" Value="{x:Null}" />

    <Style.Triggers>
        <!--  当验证出错时 (HasError = true) ,HasError属性是错误集合中有没有值 -->
        <Trigger Property="Validation.HasError" Value="true">
            <!--  启用我们上面定义的错误模板  -->
            <Setter Property="Validation.ErrorTemplate" Value="{StaticResource ValidationTextBoxTemplate}" />
            <Setter Property="BorderBrush" Value="Red" />
            <Setter Property="BorderThickness" Value="2" />
        </Trigger>
    </Style.Triggers>
</Style>

步骤三:需要使用输入验证的控件要做

XML 复制代码
 <TextBox Style="{StaticResource SensorValueStyle}">
     <TextBox.Text>
         <Binding Path="WeatherStationParametersExample.AirTemperature.Value">
//指定了验证规则,并且开启了业务逻辑验证,也就是ValidationRules
             <Binding.ValidationRules>
                 <Validation:RestrictNegativeValues />
             </Binding.ValidationRules>
         </Binding>
     </TextBox.Text>
 </TextBox>
相关推荐
小程故事多_802 小时前
Harness实战指南,在Java Spring Boot项目中规范落地OpenSpec+Claude Code
java·人工智能·spring boot·架构·aigc·ai编程
砍材农夫6 小时前
spring-ai 第四多模态API
java·人工智能·spring
她说..9 小时前
Java 对象相关高频面试题
java·开发语言·spring·java-ee
庞轩px9 小时前
深入理解 sleep() 与 wait():从基础到监视器队列
java·开发语言·线程··wait·sleep·监视器
皮皮林55110 小时前
面试官:ZSet 的底层实现是什么?
java
这是个栗子10 小时前
TypeScript(三)
前端·javascript·typescript·react
码云数智-大飞10 小时前
C++ RAII机制:资源管理的“自动化”哲学
java·服务器·php
2601_9498165810 小时前
Spring+Quartz实现定时任务的配置方法
java
计算机毕设指导611 小时前
基于SpringBoot校园学生健康监测管理系统【源码文末联系】
java·spring boot·后端·spring·tomcat·maven·intellij-idea