浅谈WPF之Binding数据校验和类型转换

在WPF开发中,Binding实现了数据在Source和Target之间的传递和流通,就像现实生活中的一条条道路,建立起了城镇与城镇之间的衔接,而数据校验和类型转换,就像高速公路之间的收费站和安检站。那在WPF开发中,如何实现数据的校验和类型转换呢?本文以一个简单的小例子,简述在WPF开发中,实现数据校验和类型转换的相关知识点,仅供学习分享使用,如有不足之处,还请指正。

在数据绑定Binding中,数据校验主要通过ValidationRules属性,数据转换主要通过Converter属性

数据校验

在WPF开发中,校验数据的有效性,主要步骤如下:

1. 实现校验规则

Binding的ValidationRules是Collection<ValidationRule>类型,是一个校验规则列表,可以支持多重校验。而ValidationRule是一个抽象类,所有要实现业务规则校验,就要继承ValidationRule并实现抽象方法。

ValidationRule的Validate方法返回一个ValidationResult对象,如果校验通过,则ValidationResult的IsValid为true,否则为false。RangeValidationRule主要校验用户输入数据的范围:

namespace WpfApp4.DataValidate
{
    public class RangeValidationRule : ValidationRule
    {
        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            double d = 0;
            if(double.TryParse(value.ToString(),out d))
            {
                if(d>=0 && d <= 100)
                {
                    return new ValidationResult(true,null);
                }
            }
            return new ValidationResult(false, "数据必须在0~100之间");
        }
    }
}

 

2. 设置规则

要想应用规则,首先需要引入规则对应的命名空间:xmlns:v="clr-namespace:WpfApp4.DataValidate"

然后设置Binding的ValidationRules规则,如下所示:

<TextBlock Text="年龄" VerticalAlignment="Center"></TextBlock>
<TextBox x:Name="tbAge" Width="120" Height="25" Margin="10" Validation.Error="tbAge_Error" VerticalContentAlignment="Center">
	<TextBox.Text>
		<Binding Path="Age" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True">
			<Binding.ValidationRules>
				<v:RangeValidationRule ValidatesOnTargetUpdated="True"></v:RangeValidationRule>
			</Binding.ValidationRules>
		</Binding>
	</TextBox.Text>
</TextBox>
<TextBlock VerticalAlignment="Center" Text="{Binding DataError}" Foreground="Red"></TextBlock>

 

关于校验规则,有以下几点需要注意:

默认情况下,认为Source的数据总是正确的,规则校验只有当Target更新时,才会生效,因为Target多为用户输入;如果当Source更新时也要生效,则需要配置ValidatesOnTargetUpdated为true。

默认情况下,校验规则返回的错误信息,是不会输出到UI的,如果要输出要UI,需要设置NotifyOnValidationError属性为true。

3. 输出校验信息

默认情况下,校验信息不会输出到UI,只是显示用户控件为红色边框,如果要输出校验信息,除了设置NotifyOnValidationError属性外,还要订阅Validation.Error事件,并在事件中处理要显示的错误信息,如下所示:

private void tbAge_Error(object sender, ValidationErrorEventArgs e)
{
	this.viewModel.ValidationErrorCommand.Execute(e);
}

 

其中上述方法中的命令为ViewModel中定义,如下所示:

public class MainWindowViewModel : ObservableObject
{
	private int age;
 
	public int Age
	{
		get { return age; }
		set { SetProperty(ref age , value); }
	}
 
	private string dataError;
 
	public string DataError
	{
		get { return dataError; }
		set { SetProperty(ref dataError , value); }
	}
 
 
	private TextBox textBox;
 
	private ICommand winLoadedCommand;
 
	public ICommand WinLoadedCommand
	{
		get {
			if (winLoadedCommand == null)
			{
				winLoadedCommand = new RelayCommand<object>(WinLoaded);
			}
			return winLoadedCommand; }
	}
 
	private void WinLoaded(object sender)
	{
		if (sender != null)
		{
			var win = sender as MainWindow;
			this.textBox = win.tbAge;
		}
	}
 
 
 
	private ICommand validationErrorCommand;
 
	public ICommand ValidationErrorCommand
	{
		get {
			if (validationErrorCommand == null)
			{
				validationErrorCommand = new RelayCommand<object>(DisplayValidationError);
			}
			return validationErrorCommand; }
	}
 
	private void DisplayValidationError(object obj)
	{
		if (Validation.GetErrors(this.textBox).Count > 0)
		{
			this.DataError= Validation.GetErrors(this.textBox)[0].ErrorContent.ToString();
		}
		else
		{
			this.DataError = string.Empty;
		}
	}
 
}

 

4. 数据校验示例演示

经过上述步骤,运行程序,如下所示:

数据类型转换

在数据绑定时,如果Source端的数据类型和Target端的数据类型不一致时,就需要用到数据类型转换,如:true/false与显示/隐藏之间的转换等,要实现数据转换,需要用到Binding的Converter属性。步骤如下:

1. 定义转换器

Binding的Converter属性是IValueConverter类型,所以定义转换器需要实现IValueConverter接口,如下所示:

namespace WpfApp4.DataConverter
{
    public class BoolToVisilityConverter : IValueConverter
    {
        /// <summary>
        /// Source 到 Target
        /// </summary>
        /// <param name="value"></param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns></returns>
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var flag = bool.Parse(value.ToString());
            if(flag)
            {
                return Visibility.Visible;
            }
            else
            {
                return Visibility.Collapsed;
            }
        }
 
        /// <summary>
        /// Target到Source
        /// </summary>
        /// <param name="value"></param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns></returns>
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var visibility = Visibility.Collapsed;
            if (Enum.TryParse<Visibility>(value.ToString(), out visibility))
            {
                if (visibility == Visibility.Collapsed)
                {
                    return false;
                }
                else if(visibility == Visibility.Visible)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
 
            return false;
        }
    }
}

 

注意:IValueConverter接口共两个方法,其中Convert方法当Source到Target时调用,ConvertBack方法则是反方向调用。

2. 定义资源

转换器也是一种资源,要声明资源,首先引入命名空间xmlns:c="clr-namespace:WpfApp4.DataConverter",如下所示:

<Window.Resources>
	<c:BoolToVisilityConverter x:Key="boolToVisility"></c:BoolToVisilityConverter>
</Window.Resources>

 

3. 调用类型转换

在Binding时,调用资源Visibility="{Binding ElementName=chk01, Path=IsChecked, Converter={StaticResource boolToVisility}}"。通过复选框的选择与否,控制控件的显示与隐藏,如下所示:

<StackPanel Orientation="Horizontal" Grid.Row="0">
	<CheckBox Content="显示" x:Name="chk01"></CheckBox>
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="1" Visibility="{Binding ElementName=chk01, Path=IsChecked, Converter={StaticResource boolToVisility}}">
	<TextBlock Text="年龄" VerticalAlignment="Center"></TextBlock>
	<TextBox x:Name="tbAge" Width="120" Height="25" Margin="10" Validation.Error="tbAge_Error" VerticalContentAlignment="Center">
		<TextBox.Text>
			<Binding Path="Age" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True">
				<Binding.ValidationRules>
					<v:RangeValidationRule ValidatesOnTargetUpdated="True"></v:RangeValidationRule>
				</Binding.ValidationRules>
			</Binding>
		</TextBox.Text>
	</TextBox>
	<TextBlock VerticalAlignment="Center" Text="{Binding DataError}" Foreground="Red"></TextBlock>
</StackPanel>

 

4. 数据类型转换示例演示

源码下载

本实例源码相对简单,如果需要源码下载,可关注公众号,回复关键字DATAVC进行获取,如下所示:

以上就是【浅谈WPF之Binding时数据校验和类型转换】的全部内容,关于更多详细内容,可参考官方文档。希望能够一起学习,共同进步。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【一起学习Arcade】(6):属性规则实例_约束规则和验证规则

一、约束规则 约束规则用于指定要素上允许的属性配置和一般关系。 与计算规则不同&#xff0c;约束规则不用于填充属性&#xff0c;而是用于确保要素满足特定条件。 简单理解&#xff0c;约束规则就是约束你的编辑操作在什么情况下可执行。 如果出现不符合规则的操作&#…

MySQL表分区技术介绍

目录 1. 分区概述 1.1 表分区 1.2 表分区与分表的区别 1.3 表分区的好处 1.4 分区表的限制因素 2. 如何判断当前MySQL是否支持分区&#xff1f; 3. 分区类型详解 3.1 MySQL支持分区类型 3.2 RANGE分区 3.2.1 根据数值范围分区 3.2.2 根据TIMESTAMP范围分区 3.2.3 根…

Vue - 调用接口获取文件数据流并根据类型预览

Vue - 调用接口获取文件数据流并根据类型预览 一、接口返回的数据流格式二. 方法实现1. image 图片类型2. txt 文件类型3. pdf 文件类型 一、接口返回的数据流格式 二. 方法实现 1. image 图片类型 <img :src"imageUrl" alt"" srcset"" /&g…

LeetCode每日一题【c++版】

20240227-困难2867-统计树中的合法路径数目 一、概述 由于比较难打&#xff0c;直接截图贴过来了&#xff01; 二、思路 预处理得到 [1,n]中的所有质数&#xff0c;其中 prime[i]是否为质数。根据二维整数整数构建图 g&#xff0c;其中 g[i]表示节点i的所有邻居节点。如果一条…

【二叉树的最近公共祖先】【后序遍历】Leetcode 236. 二叉树的最近公共祖先

【二叉树的最近公共祖先】【后序遍历】Leetcode 236. 二叉树的最近公共祖先 解法1 涉及到结果向上返回就要用后序遍历解法2 自己写的方法 后序遍历 ---------------&#x1f388;&#x1f388;236. 二叉树的最近公共祖先 题目链接&#x1f388;&#x1f388;-----------------…

外包干了6个月,技术退步明显

先说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入广州某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

群晖Synology Drive服务搭建结合内网穿透实现云同步Obsidian笔记文件夹

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-ebec69DBjtGk7apF {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

Rust学习笔记:深度解析内存管理(二)

在这个信息爆炸的时代&#xff0c;学习一门新的编程语言不仅仅是为了找到一份好工作&#xff0c;更是为了打开思维的新窗口。Rust&#xff0c;作为一门注重安全、速度和并发的系统编程语言&#xff0c;正吸引着越来越多的年轻开发者的目光。今天&#xff0c;我们将一起深入探讨…

线程的同步互斥机制3月4日

题目&#xff1a; 代码&#xff1a; #include <stdio.h> #include <pthread.h> #include <string.h> #include <semaphore.h> #include <unistd.h>sem_t sem1,sem2;void* callback1(void*arg) {while(1){if(sem_wait(&sem1)<0) //等待…

python二级常见题目

一.常见语法 jieba—第三方中文分词函数库 jieba—第三方中文分词函数库_jieba库函数-CSDN博客 Python基础——format格式化 Python基础——format格式化_python format-CSDN博客 format()方法的使用超全_format方法-CSDN博客 Python中random函数用法整理 Python中random…

判断回文字符串

判断回文字符串 题目描述&#xff1a;解法思路&#xff1a;解法代码&#xff1a;运行结果&#xff1a; 题目描述&#xff1a; 输入⼀个字符串&#xff0c;判断这个字符串是否是回文字符串&#xff08;字符串的长度小于等于30&#xff0c;字符串不包含空格&#xff09;&#xf…

聊一聊日常开发中如何优雅的避免那无处不在的空指针异常

在Java编程语言中&#xff0c;NullPointerException&#xff08;简称NPE&#xff09;是一种常见的运行时异常&#xff0c;当程序试图访问或操作一个还未初始化&#xff08;即值为null&#xff09;的对象引用时&#xff0c;Java虚拟机就会抛出NullPointerException。如果我们在日…

DataWorks(ODPS)性能优化技巧指南

使用阿里云DataWorks进行数据处理的时候&#xff0c;有时候会遇到一个sql或pyodps&#xff08;本质上还是转化为sql&#xff09;执行很长的情况&#xff0c;这个时候有必要对代码进行性能优化。 一、打开ODPS运行评估报告 一个sql脚本执行完毕后&#xff0c;在运维中心的周期…

java中Timer和Timertask的关系

一 time和timertask的关系 1.1 timer和timertask关系 1.Timer来讲就是一个调度器,而TimerTask呢只是一个实现了run方法的一个类&#xff1b; 2.Timer和TimerTask成对出现&#xff0c;Timer是定时器&#xff0c;TimerTask是定时任务。换句话说&#xff0c;定时任务TimerTask是…

程序员必备的linux常用的26条命令

04 穿越功耗墙&#xff0c;我们该从哪些方面提升“性能”&#xff1f; 上一讲&#xff0c;在讲 CPU 的性能时&#xff0c;我们提到了这样一个公式&#xff1a; 程序的 CPU 执行时间 指令数CPIClock Cycle Time 这么来看&#xff0c;如果要提升计算机的性能&#xff0c;我们可以…

鸿蒙实战开发:【SIM卡管理】

概述 本示例展示了电话服务中SIM卡相关功能&#xff0c;包含SIM卡的服务提供商、ISO国家码、归属PLMN号信息&#xff0c;以及默认语音卡功能。 样例展示 基础信息 介绍 本示例使用sim相关接口&#xff0c;展示了电话服务中SIM卡相关功能&#xff0c;包含SIM卡的服务提供商、…

Chat GPT:AI聊天机器人的革命性突破!

一、引言 近年来&#xff0c;人工智能&#xff08;AI&#xff09;技术的发展日新月异&#xff0c;其中最具代表性的成果之一便是Chat GPT。这款基于自然语言处理&#xff08;NLP&#xff09;技术的聊天机器人&#xff0c;以其高度智能、灵活多变的特点&#xff0c;迅速吸引了全…

C/C++工程师面试题(STL篇)

STL 中有哪些常见的容器 STL 中容器分为顺序容器、关联式容器、容器适配器三种类型&#xff0c;三种类型容器特性分别如下&#xff1a; 1. 顺序容器 容器并非排序的&#xff0c;元素的插入位置同元素的值无关&#xff0c;包含 vector、deque、list vector&#xff1a;动态数组…

LeetCode-第162题-寻找峰值

1.题目描述 峰值元素是指其值严格大于左右相邻值的元素。 给你一个整数数组 nums&#xff0c;找到峰值元素并返回其索引。数组可能包含多个峰值&#xff0c;在这种情况下&#xff0c;返回 任何一个峰值 所在位置即可。 你可以假设 nums[-1] nums[n] -∞ 。 你必须实现时间…

Kali Linux 2024.1

Kali Linux 2024.1刚刚发布&#xff0c;标志着这个备受欢迎的安全重点Linux发行版在今年的首次重大更新。以其先进的渗透测试和安全审计功能而闻名&#xff0c;它是安全专业人员和爱好者的首选工具。 Kali 2024.1 亮点 本次发布由 Linux 内核 6.6 提供支持&#xff0c;突出了…