背景

应用开发过程中,常常会对用户输入内容进行验证,通常是基于类型、范围、格式或者特定的要求进行验证,以确保输入符合预期。例如邮箱输入框校验输入内容是否符合邮箱格式。在WPF中,数据模型允许将ValidationRules与Binding对象关联,可以通过继承ValidationRule类并重写Validate方法来创建自定义规则。

问题

尽管创建自定义校验规则可以满足大部分应用场景,但是当我们校验规则是动态变化的时候就有些麻烦了。例如,开发一个文件管理系统,要求文件名不能与系统中已有的文件重名。这个时候需要先获取到系统中已有文件的名称列表,并绑定到ValidationRule上。然而ValidationRule不是继承于DepedencyObject,不能添加依赖属性,自定义的验证规则中的参数不支持绑定。

解决方案

接下来将给出一个解决方案,让ValidationRule支持参数绑定。思路如下:

首先自定义一个继承DepedencyObject的类ValidationParams,并在其中添加依赖属性用于绑定数据。

public class ValidationParams:DependencyObject
{
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
} public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(ValidationParams), new PropertyMetadata(null));
}

然后在自定义校验规则FileNameValidationRule中添加ValidationParams类型的属性。

public class FileNameValidationRule : ValidationRule
{
public ValidationParams Params { get; set; } public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
Regex reg = new Regex("[^()()a-zA-Z0-9_\u4e00-\u9fa5]");
if (reg.IsMatch(value.ToString()) || value.ToString().Trim() == "")
return new ValidationResult(false, "请输入字母、数字、下划线或汉字");
else if ((Params.Data as List<string>).Contains(value.ToString()))
return new ValidationResult(false, "名称重复,请修改名称");
else
return new ValidationResult(true, null);
}
}

最后在XAML中输入框数据绑定时添加校验规则,并把已有文件的名称列表绑定到校验规则参数中。

<ctoolkit:WatermarkTextBox x:Name="FileNameWTextBox" Watermark="请输入文件名称" ShowClearButton="True" Width="418" Height="30" HorizontalAlignment="Left" Margin="90,0,0,0">
<TextBox.Text>
<Binding Path="FileName" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<chelper:FileNameValidationRule>
<chelper:FileNameValidationRule.Params>
<chelper:ValidationParams Data="{Binding DataContext.ListFileName,ElementName=self}"/>
</chelper:FileNameValidationRule.Params>
</chelper:FileNameValidationRule>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</ctoolkit:WatermarkTextBox>

然而,事情并没有那么顺利,ValidationParams的Data始终是空的,也就是绑定不成功。这是为什么呢?经过研究发现,FileNameValidationRule并不在可视化树上,无法继承和访问到DataContext,因此绑定失败。

解决这个问题的方法其实也不太复杂(其实找解决办法也是花了点时间)。思路是利用资源字典和Freezable类。

  • 即使不在逻辑树中的对象也可以通过key访问到资源。
  • Freezable类的主要目的是定义具有可修改状态和只读状态的对象,但是比较幸运的是这个类的实例不在可视化树或逻辑树中也可以继承到DataContext,目前我也不清楚这里的原理。

根据这两点信息,首先定义一个继承于Freezable的类BindingProxy,包含一个用于绑定数据的依赖属性DataProperty。

public class BindingProxy : Freezable
{
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
} public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
} // Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new PropertyMetadata(null));
}

然后在WatermarkTextBox的资源字典中实例化BindingProxy,并绑定已有文件名称列表,然后在校验规则参数ValidationParams的Data中绑定BindingProxy实例。

<ctoolkit:WatermarkTextBox x:Name="FileNameWTextBox" Watermark="请输入文件名称" ShowClearButton="True" Width="418" Height="30" HorizontalAlignment="Left" Margin="90,0,0,0">
<ctoolkit:WatermarkTextBox.Resources>
<chelper:BindingProxy x:Key="FileNamesProxy" Data="{Binding DataContext.ListFileName,ElementName=self}"/>
</ctoolkit:WatermarkTextBox.Resources>
//上文中已有代码此处省略...
<chelper:ValidationParams Data="{Binding Source={StaticResource FileNamesProxy},Path=Data}"/>
//上文中已有代码此处省略...
</ctoolkit:WatermarkTextBox>

小结

在WPF中,默认情况下,DataContext是通过可视化树来传递的。父元素的DataContext会自动传递给其子元素,以便子元素可以访问父元素的数据对象。但是,不在可视化树上的对象,无法继承和直接绑定到DataContext。本文的案例也是在这个地方卡壳了,虽然最终解决了这个问题,但是Freezable类如何继承到DataContext的原理还有待研究。

如何让WPF中的ValidationRule实现参数绑定的更多相关文章

  1. WPF中的命令与命令绑定(二)

    原文:WPF中的命令与命令绑定(二) WPF中的命令与命令绑定(二)                                              周银辉在WPF中,命令(Commandi ...

  2. WPF中的命令与命令绑定导航

    1.WPF中的命令与命令绑定(一) (引入命令) 2.WPF中的命令与命令绑定(二)(详细介绍命令和命令绑定)

  3. WPF中的命令与命令绑定(一)

    原文:WPF中的命令与命令绑定(一)   WPF中的命令与命令绑定(一)                                           周银辉说到用户输入,可能我们更多地会联想到 ...

  4. WPF中PasswordBox控件无法绑定Password属性解决办法

    在WPF中,默认的Password控件的Password属性是不允许为之绑定的,下面是一个解决绑定Password的方法的代码: 1.前台代码 <Window x:Class="Pas ...

  5. (十七)springMvc 对表单提交的日期以及JSON中的日期的参数绑定

    文章目录 前言 `Ajax`提交表单数据 `Ajax`提交`JSON` 格式数据 解决输出JSON乱码的问题 控制JSON输出日期格式 小记 前言 springMVC 提供强大的参数绑定功能,使得我们 ...

  6. wpf中UserControl的几种绑定方式

    我们经常会抽取一些可重用的控件,某个属性是否需要重用,直接决定了这个属性的绑定方式. 1.完全不可重用的控件 有一些与业务强相关的控件,它们的属性完全来自ViewModel,越是相对复杂的控件,越容易 ...

  7. WPF中,多key值绑定问题,一个key绑定一个界面上的对象

    问题说明: 当用到dictionary<key,value>来储存数据的时候,有时候需要在界面上绑定一个key来显示value,这时候有两种思路: 一种是写一个自定义的扩展类,类似Bind ...

  8. 在WPF中UserControl

    在这里我们将将打造一个UserControl(用户控件)来逐步讲解如何在WPF中自定义控件,并将WPF的一些新特性引入到自定义控件中来.我们制作了一个带语音报时功能的钟表控件, 效果如下: 在VS中右 ...

  9. 在WPF中自定义控件

    一, 不一定需要自定义控件在使用WPF以前,动辄使用自定义控件几乎成了惯性思维,比如需要一个带图片的按钮,但在WPF中此类任务却不需要如此大费周章,因为控件可以嵌套使用以及可以为控件外观打造一套新的样 ...

  10. 在WPF中自定义控件(2) UserControl

    原文:在WPF中自定义控件(2) UserControl 在WPF中自定义控件(2) UserControl                                               ...

随机推荐

  1. 2020-12-08:TIME_WAIT的等待时间为什么是2MSL?

    福哥答案2020-12-08:[答案来自此链接:](http://bbs.xiangxueketang.cn/question/646)这里假设主动关闭方为A,被动关闭方为B,TIME_WAIT状态是 ...

  2. 2021-08-29:N * M的棋盘(N和M是输入参数),每种颜色的格子数必须相同的,上下左右的格子算相邻,相邻格子染的颜色必须不同,所有格子必须染色,返回至少多少种颜色可以完成任务。 福大大 答

    2021-08-29:N * M的棋盘(N和M是输入参数),每种颜色的格子数必须相同的,上下左右的格子算相邻,相邻格子染的颜色必须不同,所有格子必须染色,返回至少多少种颜色可以完成任务. 福大大 答案 ...

  3. Django 14天从小白到进阶- Day1 Django 初识

    来自作者:金角大王 本节内容 Http原理介绍 自行开发一个Web框架 WSGI介绍 Django介绍 MVC/MTV Django安装 创建项目与APP 开发第一个页面 为什么学Django? Go ...

  4. 解决:Invalid HTTP_HOST header: '192.168.56.1:8001'. You may need to add '192.168.56.1' to ALLOWED_HOSTS.

    在setting.py下的ALLOWED_HOSTS=['*']添加'*'就可以解决显示不出来的问题.

  5. proto中service 作用的理解

    转载请注明出处: 在 proto 文件中,service 用于定义一组 RPC 方法,在服务端实现这些方法,并在客户端调用这些方法进行远程过程调用. service 的定义方式如下: service ...

  6. 前端自动识别CAD图纸提取信息方法总结

    前言 CAD图纸自动识别和提取信息具有许多意义,包括以下几个方面: 提高工作效率:传统上,对于大量的CAD图纸,人工识别和提取信息是一项耗时且繁琐的任务.通过自动化这一过程,可以大大提高工作效率,节省 ...

  7. Kubernetes 证书详解(鉴权)

    Kubernetes 证书详解(鉴权) 简介 上一篇 系统分析了 Kubernetes 集群中每个证书的作用和证书认证的原理.对于 Kube-apiserver,Kubelet 来说,它们都能提供 H ...

  8. Java中的金钱陷阱

    前言 有多少小伙伴是被标题 骗 吸引进来的呢,我可不是标题党,今天的文章呢确实跟"金钱"有关系. 但是我们说的不是过度追求金钱而掉入陷阱,而是要说一说在Java程序中,各种跟金钱运 ...

  9. 掌握Python文件操作:从基础到高阶的全方位探索

    在本篇博客中,我们将全面.深入地探讨Python中的文件操作.文件操作在Python编程中是不可或缺的一部分,它包含了打开.读取.写入和关闭文件等各种操作.我们将从基础的文件操作讲解到高级的文件处理技 ...

  10. LeetCode 周赛 350(2023/06/18)01 背包变型题

    本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 和 [BaguTree Pro] 知识星球提问. 往期回顾:LeetCode 单周赛第 348 场 · 数位 DP ...