c#中使用数据验证器
前言
在很多情况下,用户的输入不一定满足我们的设计要求,需要验证输入是否正确,传统的方案是拿到控件数据进行逻辑判定验证后,给用户弹窗提示。这种方法有点职责延后的感觉,数据视图层应该很好的处理用户的输入。使用数据验证器,就可以友好的提示错误信息,让后端不用过多的验证数据正确性。
一、使用效果





二、实现代码
1、校验逻辑
public class DataErrorInfoModel:NotifyBase{private string _userName;[Required(ErrorMessage ="用户名不能为空")][StringLength(100,MinimumLength =2,ErrorMessage ="最小长度为2")]public string UserName{get { return _userName; }set{_userName = value;this.Notify();}}private string _email;[Required(ErrorMessage = "邮箱不能为空")][StringLength(100, MinimumLength = 2, ErrorMessage = "最小长度为2")][RegularExpression("^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$",ErrorMessage = "请填写正确的邮箱地址!")]public string Email{get { return _email; }set{_email = value;this.Notify();}}}
public class NotifyBase : INotifyPropertyChanged, IDataErrorInfo{public string this[string columnName]{get{var errors = new List<ValidationResult>();Validator.TryValidateProperty(this.GetType().GetProperty(columnName).GetValue(this, null),new ValidationContext(this){MemberName=columnName}, errors);if (errors.Count>0){return string.Join(Environment.NewLine, errors.Select(e => e.ErrorMessage).ToArray());}return "";}}public string Error => null ;public event PropertyChangedEventHandler PropertyChanged;public void Notify([CallerMemberName] string propName = ""){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));}}
2、WPF前台
<StackPanel Orientation="Horizontal" Grid.Row="2"><TextBox Width="200" Height="40" VerticalContentAlignment="Center" Margin="10"Template="{StaticResource ExceptionTextBoxTemplate}"Validation.ErrorTemplate="{StaticResource ExceptionTextBoxTemplate}"><TextBox.Text><Binding Path="DModel.UserName" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True"></Binding></TextBox.Text></TextBox><TextBox Width="200" Height="40" VerticalContentAlignment="Center" Margin="10"Template="{StaticResource ExceptionTextBoxTemplate}"Validation.ErrorTemplate="{StaticResource ExceptionTextBoxTemplate}"><TextBox.Text><Binding Path="DModel.Email" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True"></Binding></TextBox.Text></TextBox></StackPanel>
<ControlTemplate x:Key="ExceptionTextBoxTemplate"><Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"Background="{TemplateBinding Background}" SnapsToDevicePixels="True" CornerRadius="5"><Grid><ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" /><Border Width="16" Height="16" CornerRadius="8" Margin="5" Background="Red" VerticalAlignment="Center" HorizontalAlignment="Right" Visibility="Collapsed" Name="validation" ToolTip="{Binding (Validation.Errors)[0].ErrorContent,RelativeSource={RelativeSource AncestorType=TextBox, Mode=FindAncestor}}"><TextBlock Text="!" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" /></Border></Grid></Border><ControlTemplate.Triggers><Trigger Property="IsEnabled" Value="false"><Setter Property="Opacity" TargetName="border" Value="0.56" /></Trigger><Trigger Property="IsMouseOver" Value="true"><Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.MouseOver.Border}" /></Trigger><Trigger Property="IsKeyboardFocused" Value="true"><Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.Focus.Border}" /></Trigger><Trigger Property="Validation.HasError" Value="true"><Setter Property="BorderBrush" Value="Red" TargetName="border" /><Setter Property="Visibility" Value="Visible" TargetName="validation" /><Setter Property="ToolTip" Value="{Binding (Validation.Errors)[0].ErrorContent,RelativeSource={RelativeSource Self}}" /><!--<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />--></Trigger></ControlTemplate.Triggers></ControlTemplate>
3、控件关联(绑定数据源)
this.DataContext = new DataErrorInfoViewModel();
三、FluentValidation扩展版本
1、校验逻辑
public class TemplateMatchParamValidator : AbstractValidator<TemplateMatchParam>{public TemplateMatchParamValidator(){/** .NotNull() 属性不是 null* .NotEmpty() 属性不是 null、空字符串或空格 (或值类型的默认值, 例如 int 0)。* .NotEqual() 值不等于特定值 (或不等于其他属性的值)* .Equal() 值等于特定值 (或等于另一个属性的值)* .Length() 长度位于指定范围内。但是, 它不能确保字符串属性是否为 null。* .MaxLength() 长度不超过指定的值* .MinLength() 长度不能小于指定的值。* .LessThan() 值小于特定值 (或小于另一个属性的值)* .LessThanOrEqualTo() 值小于等于特定值 (或小于等于另一个属性的值)* .GreaterThan() 值大于特定值 (或大于另一个属性的值)* .GreaterThanOrEqualTo() 值大于等于特定值 (或大于等于另一个属性的值)* .Must() 值传递到一个委托中, 可以对该值执行自定义验证逻辑* .Matches() 正则表达式验证* .Email () 电子邮件验证** .InclusiveBetween() 介于两者之间包括边界* .ExclusiveBetween() 介于两者之间不包括边界**/RuleFor(vm => vm.Greed).NotNull().InclusiveBetween(0.01, 1).WithMessage($"请正确输入贪婪度:0.01-1");RuleFor(vm => vm.MaxOverlay).NotNull().InclusiveBetween(0.01, 1).WithMessage($"请正确输入最大重叠:0.01-1");RuleFor(vm => vm.MatchScore).NotNull().InclusiveBetween(0.1, 1).WithMessage($"请正确输入匹配分数:0.1-1");RuleFor(vm => vm.Threshold).NotNull().InclusiveBetween(10, 200).WithMessage($"请正确输入梯度阈值:10-200");RuleFor(vm => vm.MinLength).NotNull().InclusiveBetween(1, 100).WithMessage($"请正确输入最小长度:1-100");RuleFor(vm => vm.TimeOut).NotNull().InclusiveBetween(1, 10000).WithMessage($"请正确输入超时:1-10000");RuleFor(vm => vm.MinAngle).NotNull().InclusiveBetween(-180, 180).WithMessage($"请正确输入最小角度:-180-180");RuleFor(vm => vm.MaxAngle).NotNull().InclusiveBetween(-180, 180).WithMessage($"请正确输入最大角度:-180-180");RuleFor(vm => vm.MinRate).NotNull().InclusiveBetween(0.6, 1).WithMessage($"请正确输入最小比例:0.6-1");RuleFor(vm => vm.MaxRate).NotNull().InclusiveBetween(1, 1.5).WithMessage($"请正确输入最大比例:1-1.5");}}
public class TemplateMatchParam : BindableBase, IDataErrorInfo{//其他代码省略// <summary>/// 当前属性设置错误信息,用于检验用户设置的参数是否正确/// </summary>public string Error{get{var results = validator.Validate(this);if (results != null && results.Errors.Any()){var distinctRes = results.Errors.GroupBy(x => x.PropertyName).Select(y => y.FirstOrDefault());var errors = string.Join(Environment.NewLine, distinctRes.Select(x => x.ErrorMessage).ToArray());return errors;}if (LearnImage == null || !LearnImage.IsInitialized()){return "模板没有学习!";}return string.Empty;}}public string this[string columnName]{get{if (validator == null){validator = new TemplateMatchParamValidator();}var firstOrDefault = validator.Validate(this).Errors.FirstOrDefault(lol => lol.PropertyName == columnName);return firstOrDefault?.ErrorMessage;}}private TemplateMatchParamValidator validator { get; set; }}
2、WPF前台
<TextBoxGrid.Row="1"Grid.Column="1"Style="{StaticResource ParamSetHaveErrorTbStyle}"Text="{Binding TemplateMatchParam.Threshold, ValidatesOnDataErrors=True}" />
3、使用效果

相关文章:
c#中使用数据验证器
前言 在很多情况下,用户的输入不一定满足我们的设计要求,需要验证输入是否正确,传统的方案是拿到控件数据进行逻辑判定验证后,给用户弹窗提示。这种方法有点职责延后的感觉,数据视图层应该很好的处理用户的输入。使用…...
Java真人版猫爪老鼠活动报名平台系统
🐾“真人版猫爪老鼠活动报名平台系统”——趣味追逐,等你来战!🐭 🐱【萌宠变主角,现实版趣味游戏】 厌倦了电子屏幕的虚拟游戏?来试试“真人版猫爪老鼠活动”吧!在这个平台上&…...
Git原理与用法系统总结
目录 Reference前言版本控制系统Git的诞生配置Git配置用户名和邮件配置颜色配置.gitignore文件 Git的基础用法初始化仓库克隆现有的仓库添加暂存文件提交变动到仓库比较变动查看日志Git回退Git重置暂存区 Git版本管理重新提交取消暂存撤销对文件的修改 Git分支Git分支的优势Git…...
连载|浅谈红队中的权限维持(六)-Linux 主机后门与Linux 隐藏文件
本文来源无问社区,更多实战内容,渗透思路可前往查看http://www.wwlib.cn/index.php/artread/artid/11584.html 0x01 Linux 主机后门 1、添加用户 一句话添加用户 useradd test;echo -e "123456n123456n" |passwd test 或者使用 openssl …...
tomato-靶机渗透
tomato-靶机 一、安装靶机环境 下载双击.ova文件,写文件名路径导入 打开虚拟机用NAT模式 编辑–>虚拟网络编辑器查看IP段 二、信息收集 1.御剑端口扫描查找该虚拟机的IP 访问网站 扫目录 dirb http://192.168.30.130 收集到目录 /server-status /antibot_im…...
git的配置使用
第三周 Tursday 早 git日志的安装使用 [rootweb ~]# yum -y install git.x86_64 //安装软件包 [rootweb ~]# rpm -ql git //查看git的包 [rootweb ~]# mkdir /yy000 //创建新目录 [rootweb ~]# cd /yy000/ [rootweb yy000]# git init //将当前目录做为仓库…...
【1.0】drf初识
【1.0】drf初识 【一】前后端开发模式 【1】前后端混合开发 【示例】flask混合、django混合【案例】bbs项目 模板:dtl语法(django template language)模板语法 {{}} /{% %}后端渲染 qs对象–遍历循环到模板中–使用模板语法渲染渲染完成后 得到纯粹的…...
SparkSQL---编程模型的操作,数据加载与落地及自定义函数的使用
一、SparkSQL编程模型的创建与转化 1、DataFrame的构建 people.txt数据: 1 zhangsan 20 2 lisi 29 3 wangwu 25 4 zhaoliu 30 5 tianqi 35 6 kobe 40 people.json数据:在SparkSQL—简介及RDD V.S DataFrame V.S Dataset编程模型详解里 1、从Spark数据…...
文件解析漏洞--IIS--Vulhub
文件解析漏洞 一、IIS解析漏洞 用windowserver2003安装IIS测试 1.1 IIS6.X 方法一:目录解析 在网站下建立文件夹的名字为.asp/.asa的文件夹,其目录内的任何扩展名的文件都被IIS当作asp文件来解析并执行。 1.txt文件里是asp文件的语法查看当前时间 方…...
你知道缓存的这个问题到底把多少程序员坑惨了吗?
在现代系统中,缓存可以极大地提升性能,减少数据库的压力。 然而,一旦缓存和数据库的数据不一致,就会引发各种诡异的问题。 我们来看看几种常见的解决缓存与数据库不一致的方案,每种方案都有各自的优缺点 先更新缓存&…...
飞创直线模组桁架机械手优势及应用领域
随着工业自动化和智能制造的发展,直线模组桁架机械手极大地减轻了人类的体力劳动负担,在危险性、重复性高的作业环境中展现出了非凡的替代能力,引领着工业生产向自动化、智能化方向迈进。 一、飞创直线模组桁架机械手优势 飞创直线模组桁架…...
TongHttpServer 简介
1. 概述 随着网络技术的飞速发展,高并发大用户场景越来越普遍,单一应用服务节点已经不能满足并发需求,为了提高整个系统可靠性,扩展性,吞吐率,通常将多个应用服务器通过硬负载/软负载组成集群,负载均衡器根据不同负载算法将请求分发到各个应用服务器节点。 Tong…...
回溯法---组合总和
题目: 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数字可以 无限…...
将Android Library项目发布到JitPack仓库
将项目代码导入Github 1.将本地项目目录初始化为 Git 仓库。 默认情况下,初始分支称为 main; 如果使用 Git 2.28.0 或更高版本,则可以使用 -b 设置默认分支的名称。 git init -b main 如果使用 Git 2.27.1 或更低版本,则可以使用 git symbo…...
JAVAWeb实战(后端篇)
因为前后端代码内容过多,这篇只写后端的代码,前端的在另一篇写 项目实战一: 1.创建数据库,表等数据 创建数据库 create database schedule_system 创建表,并添加内容 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;-- ---------…...
【vs】实用调试技巧——学会写优秀的代码!
🦄个人主页:小米里的大麦-CSDN博客 🎏所属专栏:https://blog.csdn.net/huangcancan666/category_12718530.html ⚙️操作环境:Visual Studio 2022 目录 一、前言 二、什么是BUG? 三、调试是什么?有多重要? 一名优秀…...
数组声明方式
数组声明方式 一、 一维数组 元素数据类型[] 数组名; // 推荐元素数据类型 数组名[]; 二、 二维数组 元素数据类型[][] 数组名称; // 推荐元素数据类型 数组名称[][];元素数据类型[] 数组名称[]; 注: 对于第三种方式元素数据类型[] 数组名称[];,可…...
Docker中Docker网络-理解Docker0与自定义网络的使用示例
场景 CentOS7中Docker的安装与配置: CentOS7中Docker的安装与配置_centos docker sock-CSDN博客 在上面安装好Docker之后。 关于对Docker中默认docker0以及自定义网络的使用进行学习。 注: 博客:霸道流氓气质-CSDN博客 实现 理解dock…...
领域驱动大型结构之SYSTEM METAPHOR(系统隐喻)
在领域驱动设计(Domain-Driven Design, DDD)中,"System Metaphor" 是一种用于帮助开发团队和业务人员在理解和沟通系统时使用的概念模型。虽然 "System Metaphor" 并不是 DDD 的核心概念,但它在敏捷开发方法&…...
web前端开发一、VScode环境搭建
1、VScode安装live server插件,写完代码后,保存就会在浏览器自动更新,不需要再去浏览器点击刷新了 2、创建html文件 3、在文件中输入感叹号 ! 4、选择第一个,然后回车,就会自动输入html的标准程序 5、…...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...
