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>
相关推荐
To_OC7 小时前
LC 131 分割回文串:刚学回溯时,我连怎么切字符串都想不明白
javascript·算法·leetcode
咩咩啃树皮8 小时前
第40篇:Vue3组件化开发精讲——组件拆分、复用、父子通信、工程化架构
java·前端·架构
鱟鲥鳚9 小时前
Spring Boot 集成 LangChain4j:从模型调用到 Tool Calling(Demo版)
java·spring boot
To_OC9 小时前
LC 42 接雨水:暴力超时卡半天?前后缀数组一用就通了
javascript·算法·leetcode
小林ixn9 小时前
从 ??= 到 onKeyDown:一个 React 组件的“自我修养”
前端·javascript·react.js
এ慕ོ冬℘゜10 小时前
前端实战:jQuery 多条件联合搜索(标题模糊查询 + 日历时间段筛选)
前端·javascript·jquery
大模型码小白10 小时前
【Python零基础教程】继承、多态与魔法函数:面向对象编程三大核心特性详解
java·大数据·开发语言·人工智能·python·ai编程
随心点儿10 小时前
js postMessage 实现跨域发送消息-应用示例
javascript·ecmascript·postmessage
腾渊信息科技公司11 小时前
Spring Boot对接MES实战:视觉检测数据自动同步方案
java·人工智能·spring boot·后端·计算机视觉·ai·软件需求
爱笑的源码基地12 小时前
高并发 Redis 缓存门诊HIS系统源码,含财务统计药房进销存
java·程序·门诊系统·诊所系统·云诊所源码