WPF之绑定验证(错误模板使用)

1,前言:

         默认情况下,WPF XAML 中使用的绑定并未开启绑定验证,这样导致用户在UI上对绑定的属性进行赋值时即使因不符合规范内部已抛出异常(此情况仅限WPF中的数据绑定操作),也被程序默认忽略,UI层面也无异常提示,无法确定值是否已更改。而这些问题可通过Validation提供的附加属性,附加事件,错误模板进行检测提示,从而有效的解决绑定中产生的异常问题。

例如以下情况:

<TextBox><TextBox.Text><Binding Path="UnitCost"  >                                                       </Binding></TextBox.Text></TextBox>
public decimal UnitCost{get { return unitCost; }set{//测试UI属性绑定异常抛出捕捉if (value < 0){throw new ArgumentException("值不能小于0");}unitCost = value;OnPropertyChanged(nameof(UnitCost));}}

        在UI层面用户通过绑定将当前的 UnitCost 值设置为小于0时(仅限通过绑定输入的值),虽在代码中已产生异常,但运行程序对该绑定中产生的异常默认进行了忽略,不提示异常,导致该值是否已更新,无法确定。

2,数据验证的应用。

         数据绑定进行数据源更新时先进行验证再进行装换,所以对于文本框而言,数据在验证时都是字符串型。

2.1,开启绑定中的验证通知:NotifyOnValidationError="True"

<TextBox  Grid.Row="2" Grid.Column="1"><TextBox.Text><Binding Path="UnitCost" NotifyOnValidationError="True" ValidatesOnExceptions="True"  ></Binding></TextBox.Text></TextBox>

2.2,开启异常验证捕捉规则:ValidatesOnExceptions="True",用于捕捉在该绑定中产生的任何异常(可选)。

        此设定与以下绑定  ExceptionValidationRule 异常验证规则等同 :

<TextBox  Grid.Row="2" Grid.Column="1"><TextBox.Text><Binding Path="UnitCost" NotifyOnValidationError="True"  ><Binding.ValidationRules><ExceptionValidationRule></ExceptionValidationRule></Binding.ValidationRules></Binding></TextBox.Text></TextBox>

2.3,绑定自定义验证规则。

        自定义的验证规则类需要继承自System.Windows.Controls下的抽象类ValidationRule。

 class RangeValidationRule : ValidationRule{/// <summary>/// 范围上限/// </summary>public decimal MaxNum { get; set; } = 10000;/// <summary>/// 范围下限/// </summary>public decimal MinNum { get; set; }public override ValidationResult Validate(object value, CultureInfo cultureInfo){string valStr = value.ToString();if (string.IsNullOrEmpty(valStr)){return new ValidationResult(false, "不能为空值");}decimal val;if(!decimal.TryParse(valStr,NumberStyles.Any,cultureInfo,out val)){return new ValidationResult(false, "输入的内容非法,请输入有效的货币值");}if(val>MaxNum || val < MinNum){return new ValidationResult(false, $"只能是:{MinNum} - {MaxNum}之间的货币值");}return new ValidationResult(true, "");}}

2.4,在绑定中添加自定义的验证规则,并设置相应属性。

 <TextBox  Grid.Row="2" Grid.Column="1"><TextBox.Text><Binding Path="UnitCost" NotifyOnValidationError="True" ValidatesOnExceptions="True"  ><Binding.ValidationRules><local:RangeValidationRule MinNum="10" MaxNum="10000"></local:RangeValidationRule></Binding.ValidationRules></Binding></TextBox.Text></TextBox>

2.5,验证失败时WPF自动将控件使用的模板切换为由Validation.ErrorTemplate附加属性定义的模板。在文本框中新模板将文本框的轮过改成一条细的红色边框(默认错误模板)。

3,使用Validation提供的附加属性,附加事件对异常进行处理。

Validation.HasError附加属性,验证当前元素是否存在验证错误
Validation.Error附加事件,当前元素验证错误事件(路由事件)
Validation.Errors附加属性,当前元素产生的验证错误信息集合
Validation.ErrorTemplate附加属性,当前的元素的错误模板(模板类型:ControlTemplate)

        Validation.ErrorEvent为附加事件即为路由事件,所以可在其父容器进行注册监听。

3.1,在父容器添加附加事件,监听子元素产生的验证错误。

Validation.Error="Grid_Error"

        示例:

 <Grid Margin="10" DataContext="{Binding ElementName=listBox01, Path=SelectedItem}" Validation.Error="Grid_Error"><Grid.RowDefinitions><RowDefinition ></RowDefinition><RowDefinition ></RowDefinition><RowDefinition ></RowDefinition><RowDefinition ></RowDefinition><RowDefinition Height="3*"></RowDefinition></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="auto"></ColumnDefinition><ColumnDefinition ></ColumnDefinition></Grid.ColumnDefinitions><TextBlock Text="Model Number"></TextBlock><TextBox Grid.Column="1" Text="{Binding ModelNumber, TargetNullValue=[Empty]}"></TextBox><TextBlock Grid.Row="1" Text="Model Name"></TextBlock><TextBox Grid.Row="1" Grid.Column="1" Text="{Binding ModelName, TargetNullValue=[Empty]}"></TextBox><TextBlock Grid.Row="2" Text="Unit Cost"></TextBlock><TextBox  Grid.Row="2" Grid.Column="1"><TextBox.Text><Binding Path="UnitCost" NotifyOnValidationError="True" ValidatesOnExceptions="True"  ><Binding.ValidationRules><local:RangeValidationRule MinNum="10" MaxNum="10000"></local:RangeValidationRule></Binding.ValidationRules></Binding></TextBox.Text></TextBox><TextBlock Grid.Row="3" Text="Descriptionz:"></TextBlock><TextBox  Grid.Row="4" Grid.ColumnSpan="2" Style="{x:Null}" Text="{Binding Description}"></TextBox></Grid></Border></Grid>
  private void Grid_Error(object sender, ValidationErrorEventArgs e){if (e.Action == ValidationErrorEventAction.Added){StringBuilder sb = new StringBuilder();sb.AppendLine($"RoutedEvent:{e.RoutedEvent.Name}");sb.AppendLine($"Source:{e.Source}");sb.AppendLine($"ErrorContent:{e.Error.ErrorContent}");sb.AppendLine($"{e.Error.RuleInError.GetType().Name}");//sb.AppendLine($"Message:{e.Error.Exception.Message}");MessageBox.Show(sb.ToString());}}

3.2,根据当前元素的是否出现验证错误进行样式设置。

<Trigger Property="Validation.HasError" Value="true">

        示例:

<Trigger Property="Validation.HasError" Value="true">                               <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" >                                  </Setter></Trigger>

3.3,绑定当前元素的当前验证错误信息。

Path=(Validation.Errors)[0].ErrorContent

        示例:

 <Style.Triggers><Trigger Property="Validation.HasError" Value="true"><Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" ></Setter></Trigger></Style.Triggers>

        注意此时的附加属性样式与Path关联的附加属性样式有差异:

        Property中附加属性无括号包裹:

<Trigger Property="Validation.HasError" Value="true">

        Path中的附加属性需用括号包裹

<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" >

4,错误模板应用。

        当验证控件的Validation.HasError属性被设置为true时,WPF自动将控件使用的模板切换为由Validation.ErrorTemplate附加属性定义的模板。在文本框中新模板将文本框的轮过改成一条细的红色边框。

        ErrorTemplate的类型为ControlTemplate。

4.1,自定义错误模板。

 <Style TargetType="TextBox"><Setter Property="Margin" Value="0,3"></Setter><Setter Property="VerticalContentAlignment" Value="Center"></Setter><Setter Property="Validation.ErrorTemplate"><Setter.Value><ControlTemplate><Border BorderBrush="Green" BorderThickness="1"><DockPanel LastChildFill="True"><TextBlock  DockPanel.Dock="Right" Background="Red" ToolTip="{Binding ElementName=adornedElement1, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" HorizontalAlignment="Center">*</TextBlock><AdornedElementPlaceholder x:Name="adornedElement1"></AdornedElementPlaceholder></DockPanel></Border></ControlTemplate></Setter.Value></Setter></Style>

        错误模板是使用装饰层,装饰层位于普通窗口之上的绘图层。

<AdornedElementPlaceholder x:Name="adornedElement1"></AdornedElementPlaceholder>

        AdornedElementPlaceholder,这里指代被修饰的元素即文本框(AdornedElementPlaceholder必须位于ControlTemplate中,为固定写法。)。

4.2,通过AdornedElementPlaceholder获取被修饰对象上的验证错误信息。

<TextBlock  DockPanel.Dock="Right" Background="Red" ToolTip="{Binding ElementName=adornedElement1, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" HorizontalAlignment="Center">*</TextBlock>

5,效果

6,Demo链接:

https://download.csdn.net/download/lingxiao16888/89263053

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/319495.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#调用skiasharp操作并绘制图片

之前学习ViewFaceCore时采用Panel控件和GDI将图片及识别出的人脸方框和关键点绘制出来&#xff0c;本文将其修改为基于SKControl和SKCanvas实现相同的显示效果并支持保存为本地图片。   新建Winform项目&#xff0c;在Nuget包管理器中搜索并安装一下SkiaSharp和ViewFaceCore…

AD单通道/多通道

1.AD单通道&#xff08;单次转换&#xff0c;非扫描模式&#xff09; 1.1 接线图 1.2 AD.c #include "stm32f10x.h" // Device headervoid AD_Init(void) {RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIOA时钟RCC_APB2PeriphCl…

node.js 解析post请求 方法二

前提&#xff1a;以前面发的node.js解析post请求方法一为模板&#xff0c;具体见 http://t.csdnimg.cn/ABaIn 此文我们运用第二种方法&#xff1a;使用第三方模块formidable对post请求进行解析。 1》代码难点 *** 在Node.js中使用formidable模块来解析POST请求主要涉及到处理…

OpenWRT部署Zerotier虚拟局域网实现内网穿透

前言 细心的小伙伴肯定已经发现了&#xff1a;电脑上部署了Zerotier&#xff0c;如果路由器也部署了OpenWRT&#xff0c;那是否能远程访问呢&#xff1f; 答案是肯定的。 OpenWRT部署Zerotier有啥好处&#xff1f; 那好处必须多&#xff0c;其中的一个便是在外远程控制家里…

初识MVC

初识MVC 理论部分 今天第一次学MVC&#xff0c;拿到一个练手项目。现在来记录一下学习过程。 项目的背景就是个学生管理系统。我只做后端。 从大的来说MVC将应用程序分为三个主要组件&#xff08;部分&#xff09;&#xff1a; 模型&#xff08;Model&#xff09;是应用程序…

sql 中having和where区别

where 是用于筛选表中满足条件的行&#xff0c;不可以和聚类函数一起使用 having 是用于筛选满足条件的组 &#xff0c;可与聚合函数一起使用 所以having语句中不能使用select中定义的名字

Hive大数据任务调度和业务介绍

目录 一、Zookeeper 1.zookeeper介绍 2.数据模型 3.操作使用 4.运行机制 5.一致性 二、Dolphinscheduler 1.Dolphinscheduler介绍 架构 2.架构说明 该服务内主要包含: 该服务包含&#xff1a; 3.FinalShell主虚拟机启动服务 4.Web网页登录 5.使用 5-1 安全中心…

C++中的reverse_iterator迭代器结构设计

目录 reverse_iterator迭代器结构设计 reverse_iterator迭代器基本结构设计 operator*()函数 operator()函数 operator->()函数 operator!()函数 rbegin()函数 rend()函数 operator--()函数 operator()函数 测试代码 const_reverse_iterator迭代器设计 reverse…

安全再升级,亚信安慧AntDB数据库与亚信安全二次牵手完成兼容性互认证

日前&#xff0c;湖南亚信安慧科技有限公司&#xff08;简称&#xff1a;亚信安慧&#xff09;的产品与亚信科技&#xff08;成都&#xff09;有限公司&#xff08;简称&#xff1a;亚信安全&#xff09;再次携手&#xff0c;完成亚信安慧AntDB数据库与亚信安全IPoE接入认证系统…

Ftrans文件外发系统 构建安全可控文件外发流程

文件外发系统是企业数据安全管理中的关键组成部分&#xff0c;它主要用于处理企业内部文件向外部传输的流程&#xff0c;确保数据在合法、安全、可控的前提下进行外发。 文件外发系统的主要作用包括&#xff1a; 1、防止数据泄露&#xff1a;通过严格的审批流程和安全策略&…

节能洗车房车牌识别项目实战

项目背景 学电子信息的你加入了一家节能环保企业&#xff0c;公司的主营产品是节能型洗车房。由于节水节电而且可自动洗车&#xff0c;产品迅速得到了市场和资本的认可。公司决定继续投入研发新一代产品&#xff1a;在节能洗车房的基础上实现无人值守的功能。新产品需要通过图…

Altium Designer——第一课

一个电子设计包含四个部分&#xff1a; 1.原理图库的设计 2.原理图的设计 3.PCB封装库的设计 4.PCB布局和PCB布线的设计 电子设计工程包含的部分&#xff1a; Free documents&#xff1a; 在我们保存AD工程的文件夹中&#xff0c;如果打开的是prjpcb后缀的工程文件&#xf…

《Fundamentals of Power Electronics》——基础交流建模方法

PWM整流器小信号交流模型建模的主要步骤为&#xff1a; (a)利用小纹波近似的动态版本&#xff0c;建立与电感和电容波形的低频平均值有关的方程&#xff1b; (b)平均方程的扰动和线性化&#xff1b; (c)交流等效电路模型的建立。 以下图buck-boost电路为例进行分析。 首先测…

二叉树的迭代遍历 | LeetCode 144. 二叉树的前序遍历、LeetCode 94. 二叉树的中序遍历、LeetCode 145. 二叉树的后序遍历

二叉树的前序遍历&#xff08;迭代法&#xff09; 1、题目 题目链接&#xff1a;144. 二叉树的前序遍历 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3]示例 2&#x…

【Java】实现一个简单的线程池

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 目录 ​编辑 一、线程池的模式 二、线程池的一些参数 三、代码实现 1.BlockingQueue 2.ThreadPool 四、拒绝策略 一、线程池的模式 线程池顾名思义就是管理线程的一个池子&#xff0c;我们把创建线程的过程交给…

Neo4j v5 中 Cypher 的变化

How Cypher changed in Neo4j v5 Neo4j v5 中 Cypher 的变化 几周前&#xff0c;Neo4j 5 发布了。如果你像我一样&#xff0c;在 Neo4j 4 的后期版本中忽略了所有的弃用警告&#xff0c;你可能需要更新你的 Cypher 查询以适应最新版本的 Neo4j。幸运的是&#xff0c;新的 Cyp…

SpringBoot自定义定时任务

通常&#xff0c;在我们的项目中需要定时给前台发送一些提示性消息或者我们想要的定时信息&#xff0c;这个时候就需要使用定时任务来实现这一功能&#xff0c;实现也很简单&#xff0c;接下来具体来看看吧~ 简单定时任务 首先&#xff0c;你需要在你的启动类上加上开启定时任…

Python-VBA函数之旅-oct函数

目录 一、oct函数的常见应用场景 二、oct函数使用注意事项 三、如何用好oct函数&#xff1f; 1、oct函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a;神奇夜光杯-CSDN博客 一、oct函数的常见应用场景 oc…

docker部署nginx并实现https

文章目录 docker部署nginx并实现https1、服务器环境2、安装docker3、准备证书4、准备nginx配置文件和dockerfile文件5、创建nginx镜像与容器6、验证访问 docker部署nginx并实现https 1、服务器环境 [rootliuyanfen12 ~]#systemctl stop firewalld [rootliuyanfen12 ~]#setenf…

WORD排版常见问题与解决方案

前言 近期使用word软件进行论文排版工作&#xff0c;遇到了一些常见的问题&#xff0c;记录一下&#xff0c;避免遗忘。 基本配置 系统环境&#xff1a;win10/win11 word版本&#xff1a;Microsoft Office LTSC 专业增强版 2021 问题与解决方案 问题1&#xff1a;页眉显示内…