WPF 数据验证中的绑定失败

     2023-02-22     306

关键词:

【中文标题】WPF 数据验证中的绑定失败【英文标题】:Failed Binding in WPF Data Validation 【发布时间】:2012-12-22 13:32:54 【问题描述】:

我正在尝试将我的控件样式中的属性绑定到控件中定义的属性。该控件继承自 TextBox,称为 ChangeTextBoxWithRangeUnits。我正在尝试从我创建的 ValidationRule 类绑定到它们。这是我尝试验证文本的设置器

 <Setter Property="Text">
        <Setter.Value>
            <Binding RelativeSource="RelativeSource Self"
                     Path="Text"
                     NotifyOnValidationError="True">
                <Binding.ValidationRules>
                    <basic:DoubleValidationRule>
                        <basic:DoubleValidationRule.MinMaxDependencyObject>
                            <basic:MinMaxDependencyObject Minimum="Binding RelativeSource=RelativeSource Mode=FindAncestor, AncestorType=x:Type local:ChangeTextBoxWithRangeUnits, Path=MinimumValue"
                                                          Maximum="Binding RelativeSource=RelativeSource Mode=FindAncestor, AncestorType=x:Type local:ChangeTextBoxWithRangeUnits, Path=MaximumValue" />
                        </basic:DoubleValidationRule.MinMaxDependencyObject>
                    </basic:DoubleValidationRule>
                </Binding.ValidationRules>
            </Binding>
        </Setter.Value>
    </Setter>

我不明白为什么它说找不到源绑定。这是错误:

System.Windows.Data 错误:4:找不到与引用“RelativeSource FindAncestor,AncestorType='Frasca.Simplicity.Controls.UnitControls.ChangeTextBoxWithRangeUnits',AncestorLevel='1''的绑定源。绑定表达式:路径=最小值;数据项=空;目标元素是“MinMaxDependencyObject”(HashCode=16320155);目标属性是“最小”(类型“双”)

编辑完整的 XAML

 <Style x:Key="ChangeTextBoxWithRangeUnits"
       TargetType="x:Type local:ChangeTextBoxWithRangeUnits"
       BasedOn="StaticResource x:Type TextBox">
    <Setter Property="Validation.ErrorTemplate"
            Value="x:Null" />
    <Setter Property="Height"
            Value="64" />
    <Setter Property="FontSize"
            Value="22" />
    <Setter Property="Margin"
            Value="5" />
    <Setter Property="Background"
            Value="LightGray" />
    <Setter Property="BorderThickness"
            Value="0" />
    <Setter Property="KeyboardNavigation.TabNavigation"
            Value="None" />
    <Setter Property="AllowDrop"
            Value="true" />
    <Setter Property="ScrollViewer.PanningMode"
            Value="VerticalFirst" />
    <Setter Property="Stylus.IsFlicksEnabled"
            Value="False" />
    <Setter Property="Text">
        <Setter.Value>
            <Binding RelativeSource="RelativeSource Self"
                     Path="Text"
                     NotifyOnValidationError="True">
                <Binding.ValidationRules>
                    <basic:DoubleValidationRule>
                        <basic:DoubleValidationRule.MinMaxDependencyObject>
                            <basic:MinMaxDependencyObject Minimum="Binding RelativeSource=RelativeSource Mode=FindAncestor, AncestorType=x:Type local:ChangeTextBoxWithRangeUnits, Path=MinimumValue"
                                                          Maximum="Binding RelativeSource=RelativeSource Mode=FindAncestor, AncestorType=x:Type local:ChangeTextBoxWithRangeUnits, Path=MaximumValue" />
                        </basic:DoubleValidationRule.MinMaxDependencyObject>
                    </basic:DoubleValidationRule>
                </Binding.ValidationRules>
            </Binding>
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="x:Type local:ChangeTextBoxWithUnits">
                <Grid>
                    <Border Name="bg"
                            Background="TemplateBinding Background"
                            BorderBrush="TemplateBinding BorderBrush"
                            BorderThickness="TemplateBinding BorderThickness"
                            Width="TemplateBinding Width"
                            CornerRadius="15"
                            SnapsToDevicePixels="true">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="3*" />
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="2*" />
                            </Grid.RowDefinitions>

                            <StackPanel Orientation="Horizontal"
                                        Grid.Row="0"
                                        Name="mValueStackPanel"
                                        VerticalAlignment="Bottom"
                                        HorizontalAlignment="Center">
                                <ScrollViewer x:Name="PART_ContentHost"
                                              SnapsToDevicePixels="TemplateBinding SnapsToDevicePixels" />
                                <TextBox Name="PART_UnitTextBlock"
                                         Style="DynamicResource InlineTextBox"
                                         Text="Binding RelativeSource=RelativeSource FindAncestor, AncestorType=x:Type local:ChangeTextBoxWithUnits, Path=Units"
                                         FontSize="14"
                                         Margin="3,0,0,0"
                                         Foreground="TemplateBinding Foreground" />
                            </StackPanel>

                            <StackPanel Orientation="Horizontal"
                                        Grid.Row="2"
                                        HorizontalAlignment="Center"
                                        VerticalAlignment="Top">
                                <TextBlock Text="Binding RelativeSource=RelativeSource FindAncestor, AncestorType=x:Type local:ChangeTextBoxWithUnits, Path=Label"
                                           FontSize="14"
                                           Foreground="TemplateBinding Foreground" />
                            </StackPanel>

                            <TextBlock Text="Binding RelativeSource=RelativeSource FindAncestor, AncestorType=x:Type local:ChangeTextBoxWithUnits, Path=DisabledText"
                                       Foreground="TemplateBinding Foreground"
                                       Grid.Row="0"
                                       FontSize="14"
                                       HorizontalAlignment="Center"
                                       VerticalAlignment="Bottom"
                                       Visibility="Collapsed"
                                       x:Name="mDisabledTextBlock" />

                            <!-- Horizontal line -->
                            <Rectangle Height="1"
                                       Margin="10,0"
                                       Grid.Row="1"
                                       Opacity="0.15"
                                       SnapsToDevicePixels="True"
                                       Fill="TemplateBinding Foreground" />

                            <!-- Object which flashes when the textbox is selected -->
                            <Border Grid.RowSpan="3"
                                    Background="White"
                                    Name="FlashObject"
                                    CornerRadius="15"
                                    Opacity="0">
                                <Border.Effect>
                                    <BlurEffect Radius="20" />
                                </Border.Effect>
                            </Border>

                            <!-- Object which flashes when the textbox has a validation error-->
                            <Border Grid.RowSpan="3"
                                    Grid.ColumnSpan="2"
                                    Background="Red"
                                    Name="ErrorFlashObject"
                                    CornerRadius="15"
                                    Opacity="0">
                                <Border.Effect>
                                    <BlurEffect Radius="20" />
                                </Border.Effect>
                            </Border>
                        </Grid>
                    </Border>

                    <!-- Object which glows when the user makes a change to the text value. -->
                    <Border Width="Binding ElementName=bg, Path=ActualWidth"
                            Height="Binding ElementName=bg, Path=ActualHeight"
                            CornerRadius="15"
                            Background="#FFF066"
                            Name="ChangeGlowObject"
                            Panel.ZIndex="-1"
                            Visibility="Collapsed">
                        <Border.Effect>
                            <BlurEffect Radius="20" />
                        </Border.Effect>
                    </Border>
                </Grid>
                <ControlTemplate.Triggers>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="HasChangedValue"
                                       Value="True" />
                            <Condition Property="IsEnabled"
                                       Value="True" />
                        </MultiTrigger.Conditions>
                        <Setter Property="Visibility"
                                TargetName="ChangeGlowObject"
                                Value="Visible" />
                    </MultiTrigger>
                    <Trigger Property="IsEnabled"
                             Value="False">
                        <Setter Property="Background"
                                Value="#686868" />
                    </Trigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsEnabled"
                                       Value="False" />
                            <!--<Condition Property="ShowTextWhenDisabled"
                                       Value="False" />-->
                        </MultiTrigger.Conditions>
                        <Setter Property="Visibility"
                                TargetName="mDisabledTextBlock"
                                Value="Visible" />
                        <Setter Property="Visibility"
                                TargetName="mValueStackPanel"
                                Value="Collapsed" />
                    </MultiTrigger>

                    <!-- trigger to flash the object when the textbox has an error -->
                    <Trigger Property="Validation.HasError"
                             Value="True">
                        <Trigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation BeginTime="00:00:00"
                                                     Duration="00:00:00.2"
                                                     From="0"
                                                     To="1"
                                                     Storyboard.TargetName="ErrorFlashObject"
                                                     Storyboard.TargetProperty="Opacity">
                                        <DoubleAnimation.EasingFunction>
                                            <PowerEase Power="2"
                                                       EasingMode="EaseIn" />
                                        </DoubleAnimation.EasingFunction>
                                    </DoubleAnimation>
                                    <DoubleAnimation BeginTime="00:00:00.2"
                                                     Duration="00:00:00.5"
                                                     From="1"
                                                     To="0"
                                                     Storyboard.TargetName="ErrorFlashObject"
                                                     Storyboard.TargetProperty="Opacity">
                                        <DoubleAnimation.EasingFunction>
                                            <PowerEase Power="2"
                                                       EasingMode="EaseIn" />
                                        </DoubleAnimation.EasingFunction>
                                    </DoubleAnimation>
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.EnterActions>
                    </Trigger>

                    <!-- trigger to flash the object when the textbox is selected -->
                    <EventTrigger RoutedEvent="FocusManager.GotFocus">
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation BeginTime="00:00:00"
                                                 Duration="00:00:00.2"
                                                 From="0"
                                                 To="1"
                                                 Storyboard.TargetName="FlashObject"
                                                 Storyboard.TargetProperty="Opacity">
                                    <DoubleAnimation.EasingFunction>
                                        <PowerEase Power="2"
                                                   EasingMode="EaseIn" />
                                    </DoubleAnimation.EasingFunction>
                                </DoubleAnimation>
                                <DoubleAnimation BeginTime="00:00:00.2"
                                                 Duration="00:00:00.5"
                                                 From="1"
                                                 To="0"
                                                 Storyboard.TargetName="FlashObject"
                                                 Storyboard.TargetProperty="Opacity">
                                    <DoubleAnimation.EasingFunction>
                                        <PowerEase Power="2"
                                                   EasingMode="EaseIn" />
                                    </DoubleAnimation.EasingFunction>
                                </DoubleAnimation>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

【问题讨论】:

您能否添加一个完整的 XAML 示例? 【参考方案1】:

RelativeSource 绑定不会沿着您的 XML 前进,它们会沿着 Visual Tree 前进。这意味着您可以在您绑定的元素在该树中时使用它。

在这种情况下,您的DoubleValidationRule 不是 UIElement,并且它在可视化树中不是,因此RelativeSouce 在此规则上的绑定将失败。

不幸的是,在不知道您的DoubleValidationRule.MinMaxDependencyObject 的实现或目的的情况下,很难说您应该做什么。您可以通过更改验证规则的实现来绕过此限制。

一种可行的方法是,您可以通过 x:Name 值引用树中的元素

Minimum="Binding MinimumValue, ElementName=TheMinimumTarget

但这可能意味着您不能使用 Style 来执行此操作,因为每次使用都会(可能)绑定到表单上的不同元素。


查看您的编辑... Wat?您要将控件的文本绑定到控件的文本以附加验证规则吗?那是……我什至没有。

我建议对控件进行子类化以添加验证逻辑(例如,覆盖 Text 依赖属性的属性元数据),然后将您的模板应用于这种新类型。

【讨论】:

对,这是一种风格,所以我不能应用名称。 MinMaxDependencyObject 是一个简单的类,它继承具有最小值和最大值的 DependencyObject。它的唯一目的是让我可以对 DoubleValidationRule 使用绑定。你有什么建议吗?谢谢。

WPF 数据绑定和验证规则最佳实践

】WPF数据绑定和验证规则最佳实践【英文标题】:WPFDataBindingandValidationRulesBestPractices【发布时间】:2010-09-0823:36:42【问题描述】:我有一个非常简单的WPF应用程序,我在其中使用数据绑定来允许编辑一些自定义CLR对象。我现在想... 查看详情

在 WPF 中验证几个链接的数据绑定文本框值

】在WPF中验证几个链接的数据绑定文本框值【英文标题】:ValidatingseverallinkeddataboundTextBoxvaluesinWPF【发布时间】:2010-01-1501:46:04【问题描述】:我正在尝试寻找一种优雅的方式来验证WPF中两个相关的TextBox值。每个文本框的Text属... 查看详情

wpf入门教程系列十五——wpf中的数据绑定

...n(WPF)可以很方便的设计出强大的用户界面,同时WPF提供了数据绑定功能。WPF的数据绑定跟Winform与ASP.NET中的数据绑定功能类似,但也有所不同,在WPF中以通过后台代码绑定、前台XAML中进行绑定,或者两者组合的方式进行数据绑定... 查看详情

WPF双向绑定不起作用

...4-04-1018:49:44【问题描述】:我有一个分配给我的主窗口的数据上下文(UserPreferences),以及一个文本框,它双向绑定到上下文中数据上下文属性(CollectionDevice)中的一个属性。当窗口加载时,文本框不会绑定到我模型中的属性。我在... 查看详情

再谈wpf

...一步的理解,记录下来,以备后期查看。首先,在WPF中,数据绑定很重要,也是WPF的核心。数据绑定和命令的绑定,需要后台来实现,主要是ViewModel来实现。ViewModel中主要包含以下几项:1、页面中所用到的参数,包括数据源和... 查看详情

数据绑定如何避免 WPF 中的递归更新?

】数据绑定如何避免WPF中的递归更新?【英文标题】:HowdoesdatabindingavoidrecursiveupdateinWPF?【发布时间】:2011-02-2122:29:57【问题描述】:我正在研究WPF中的绑定,然后我有一个问题:假设依赖属性绑定到实现INotifyPropertyChanged接口的... 查看详情

数据绑定到 WPF 中的方法

】数据绑定到WPF中的方法【英文标题】:DatabindingtoamethodinWPF【发布时间】:2010-02-2107:37:06【问题描述】:我在将TextBox.Text属性数据绑定到对象的方法时遇到问题。这个想法是允许用户在TextBox中写入一个文件名,然后让TextBlock输... 查看详情

wpf中的数据绑定

WPF中的数据绑定绑定模式  通过上一文章中的示例,学习了简单的绑定方式。在这里的示例,要学习一下绑定的模式,和模式的使用效果。  首先,我们来做一个简单示例,这个示例是根据ListBox中的选中项&#... 查看详情

wpf中的数据绑定

WPF中的数据绑定绑定模式  通过上一文章中的示例,学习了简单的绑定方式。在这里的示例,要学习一下绑定的模式,和模式的使用效果。  首先,我们来做一个简单示例,这个示例是根据ListBox中的选中项&#... 查看详情

WPF 中的数据网格绑定

】WPF中的数据网格绑定【英文标题】:DatagridbindinginWPF【发布时间】:2011-08-1404:01:09【问题描述】:我知道这已经被问过了,但我已经做了开发人员建议的几乎所有事情。<DataGridx:Name="Imported"VerticalAlignment="Top"DataContext="BindingSour... 查看详情

wpf---数据绑定之validationrule数据校验

...述我们知道,Binding好比架设在Source和Target之间的桥梁,数据可以借助这个桥梁进行流通。在数据流通的过程中,我们可以在Binding这座桥梁上设置关卡,对数据的有效性进行验证。二、验证方法我们利用Binding的ValidationRules(类型... 查看详情

wpf入门教程系列十七——wpf中的数据绑定

四、XML数据绑定   这次我们来学习新的绑定知识,XML数据绑定。XmlDataProvider用来绑定XML数据,该XML数据可以是嵌入.Xmal文件的XmlDataProvider标记中,也可以是外部位置引用的文件中。    当然嵌入式XML内容... 查看详情

2021-09-15wpf上位机16-属性绑定(数据验证)(代码片段)

<Windowx:Class="Zhaoxi.BindingStudy.DataValidationStudy.DataValidationStudyWin"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml 查看详情

wpf入门教程系列十八——wpf中的数据绑定

六、排序    如果想以特定的方式对数据进行排序,可以绑定到CollectionViewSource,而不是直接绑定到ObjectDataProvider。CollectionViewSource则会成为数据源,并充当截取ObjectDataProvider中的数据的媒介,并提供排序、分组和... 查看详情

数据绑定到 WPF 中的 UserControl

】数据绑定到WPF中的UserControl【英文标题】:DatabindingtoaUserControlinWPF【发布时间】:2010-07-1614:07:28【问题描述】:我有一个想要参与数据绑定的UserControl。我已经在用户控件中设置了依赖属性,但无法正常工作。当我用静态文本(... 查看详情

2021-09-29wpf上位机50-mvvm模式数据绑定(代码片段)

MVVM模式中的基本内容绑定1、数据绑定:依赖属性:数据Model必须继承DependencyObject属性名称+Changed事件:固定写法INotifyPropertyChanged接口:形成一种契约2、基于Model的数据验证ExceptionRequired、StringLength、Range、RegularExpression、CustomMode... 查看详情

将枚举属性数据绑定到 WPF 中的组合框

】将枚举属性数据绑定到WPF中的组合框【英文标题】:DatabindinganenumpropertytoaComboBoxinWPF【发布时间】:2010-09-0816:39:57【问题描述】:以如下代码为例:publicenumExampleEnumFooBar,BarFoopublicclassExampleClass:INotifyPropertyChangedprivateExampleEnumexamp... 查看详情

将枚举属性数据绑定到 WPF 中的组合框

】将枚举属性数据绑定到WPF中的组合框【英文标题】:DatabindinganenumpropertytoaComboBoxinWPF【发布时间】:2010-09-0816:39:57【问题描述】:以如下代码为例:publicenumExampleEnumFooBar,BarFoopublicclassExampleClass:INotifyPropertyChangedprivateExampleEnumexamp... 查看详情