首页 > 其他分享 >如何让WPF中的ValidationRule实现参数绑定

如何让WPF中的ValidationRule实现参数绑定

时间:2023-08-18 09:02:04浏览次数:33  
标签:ValidationRule 绑定 ValidationParams new WPF Data public

背景

应用开发过程中,常常会对用户输入内容进行验证,通常是基于类型、范围、格式或者特定的要求进行验证,以确保输入符合预期。例如邮箱输入框校验输入内容是否符合邮箱格式。在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的原理还有待研究。

标签:ValidationRule,绑定,ValidationParams,new,WPF,Data,public
From: https://www.cnblogs.com/czwy/p/17638959.html

相关文章

  • 【愚公系列】2023年08月 WPF控件专题 Label、TextBox、PasswordBox控件介绍
    (文章目录)前言WPF控件是WindowsPresentationFoundation(WPF)中的基本用户界面元素。它们是可视化对象,可以用来创建各种用户界面。WPF控件可以分为两类:原生控件和自定义控件。原生控件是由Microsoft提供的内置控件,如Button、TextBox、Label、ComboBox等。这些控件都是WPF中常见......
  • WPF --- 非Button自定义控件实现点击功能
    引言今天在做一个设置文件夹路径的功能,就是一个文本框,加个按钮,点击按钮,弹出FolderBrowserDialog再选择文件夹路径,简单做法,可以直接StackPanel横向放置一个TextBox和一个ImageButton,然后点击按钮在后台代码中给ViewModel的FilePath赋值。但是这样属实不够优雅,UI不够......
  • [WPF]WPF中MVVM模式按下ESC键退出窗口
    首先在XAML中定义监听按键<Window.InputBindings><KeyBindingKey="Esc"Command="{BindingCloseWindowCommand}"CommandParameter="{BindingRelativeSource={RelativeSourceFindAncestor,Ancest......
  • WPF-超市管理系统
    1.新建WPFAPP(netframework)项目  ......
  • Vue 样式绑定
    绑定HTMLclass:class (v-bind:class 的缩写) :class 指令也可以和一般的 class attribute共存绑定的对象并不一定需要写成内联字面量的形式,也可以直接绑定一个对象可以给 :class 绑定一个数组来渲染多个CSSclass绑定内联样式:style 支持绑定JavaScript对象......
  • Wpf Thumb 默认样式存档,方便手头没有 vs 时查阅.
    1<StyleTargetType="{x:TypeThumb}">2<SetterProperty="Stylus.IsPressAndHoldEnabled"Value="false"/>3<SetterProperty="Background"Value="{DynamicResource{x:StaticSystemColors.C......
  • C# .NET6 WPF 依赖注入
    入口文件:App.xaml.csusingMicrosoft.EntityFrameworkCore;usingMicrosoft.Extensions.Configuration;usingMicrosoft.Extensions.DependencyInjection;usingSerilog;usingSystem;usingSystem.IO;usingSystem.Text;usingSystem.Windows;namespaceDemo{......
  • 自定义MarkupExtension的学习,以及WPF中Combobox绑定枚举类型
    我们上一期讲到ComBobox绑定数据,https://www.cnblogs.com/guchen33/p/17630808.html这次我们简单化一下,正常来讲WPF中绑定不了枚举的像这样//前台代码<ComboBoxItemsSource="{BindingMyEnum}"/>//后台VMpublicenumMyEnum{One,Two,Three,Fo......
  • WPF如何构建MVVM+Prism+HandyControl ,模块化的桌面应用
    为何模块化模块化是一种分治思想,不仅可以分离复杂的业务逻辑,还可以进行不同任务的分工。模块与模块之间相互独立,从而构建一种松耦合的应用程序,便于开发和维护。开发技术.Net6+WPF+Prism(v8.0.0.1909)+HandyControl(v3.4.0)知识准备什么是MVVMModel-View-ViewModel......
  • 【校招VIP】前端vue考点之生命周期和双向绑定
    考点介绍:VUE是前端校招面试的重点,而生命周期和双向绑定又是基础考点之一,尤其在一二线公司,要求知道双向绑定的原理,以及相关代码实现。一、考点题目1、mvvm和mvc区别?它和其它框架(jquery)的区别是什么?哪些场景适合?解答:mvc和mvvm其实区别并不大。都是一种设计思想。主要就是mvc中Co......