背景

应用开发过程中,常常会对用户输入内容进行验证,通常是基于类型、范围、格式或者特定的要求进行验证,以确保输入符合预期。例如邮箱输入框校验输入内容是否符合邮箱格式。在WPF中,数据模型允许将ValidationRulesBinding对象关联,可以通过继承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. .join()字符串操作函数

    join函数是一个字符串操作函数 str.join(item)str表示字符串(字符),item表示一个成员,注意括号里必须只能有一个成员,比如','.join('a','b')这种写法是行不通的 举 ...

  2. vue全家桶进阶之路6:Vue的安装以及js引入

    1.安装 注意:Vue 不支持 IE8 及以下版本 创建一个文件夹用于下载引入Vue D:\BaiduSyncdisk\vue2 按照最新版本的Vue npm install vue 创建完成后便可以 ...

  3. WSGI实现一个WEB服务

  4. boot-admin 项目数据库缺省字段设计之最佳实践

    数据库(Database)中的缺省字段(也称为默认字段),就是在一般情况下,每个数据表(Table)必须包含的字段(Field),这类字段用于满足特定的数据需求,字段值的填充或更改一般遵照一定的逻辑要 ...

  5. Lombok注解及其作用

    Lombok是一个Java库,通过使用注解简化Java类的开发,减少冗余的样板代码.以下是一些常用的Lombok注解及其作用: 1. `@Data`:生成所有属性的getter.setter.`toS ...

  6. 疑难杂记:Chirp信号相关的参数解释

    图1 FMCW雷达信号参数 在德州仪器TI毫米波雷达中,开发板参数配置往往涉及如图1所示的信号参数. 宏观上看,信号参数包括\(ADC\)采样时间.脉冲重复周期(\(Chirp\)扫频周期)和帧时间( ...

  7. 【对比】ChatGPT Plus与ChatGPT实操对比体验

    前言 缘由 20美刀大洋充值ChatGPT Plus,必须分享让它物尽其用 应单位追求科技前沿需求,以及花钱就是香的原则.遂找了远在他乡的高中老同学,斥资20美刀为公司身先士卒怒充会员.秉承分享至上原 ...

  8. MyBatis-plus乐观锁

    什么是乐观锁呢?为什么要使用这个功能?这个功能能做什么呢?如何使用这个? 1.乐观锁( Optimistic Locking ) 是相对悲观锁而言的,乐观锁是假设认为数据一般情况下不会造成冲突,所以在 ...

  9. Dlang 并行化

    Dlang 并行化 好难受,dlang 生态太差,没办法,学了半天才明白. 我尽量以精炼的语言解释. 采用 定义,例子(代码),解释 的步骤讲解. 所以你可能看到很多代码,一点解释-- 我会省略一些 ...

  10. FreeFileSync结合任务计划实现T级数据的全量备份和每日十几G数据的增量自动备份

    1. 背景 公司现有nas存储中有共计1.8T左右的文件数据(一般是pdf.excel.图片.压缩文件等等格式),因为nas无法做备份:担心后面nas出现故障造成数据丢失,现急需一个解决方案实现如下目 ...