C# UserControl的WPF样式验证错误

C# UserControl的WPF样式验证错误,c#,wpf,validation,xaml,user-controls,C#,Wpf,Validation,Xaml,User Controls,我已经使用DataAnnotations和INotifyDataError在应用程序中实现了验证,并且可以成功地显示何时发生错误以及错误是什么。我希望将默认错误模板更改为输入值的文本框的样式 如果TextBox与创建底层数据模型绑定的用户控件位于同一个UserControl中,那么这对我来说是正确的 然而,我有很多输入,因此决定提取一个UserControl来封装标签和文本框。问题是,这样做后,我无法再获取文本框来指示错误,我将获取整个控件周围的默认红色框 我尝试了一些建议,比如让孩子控件实现I

我已经使用DataAnnotations和INotifyDataError在应用程序中实现了验证,并且可以成功地显示何时发生错误以及错误是什么。我希望将默认错误模板更改为输入值的文本框的样式

如果TextBox与创建底层数据模型绑定的用户控件位于同一个UserControl中,那么这对我来说是正确的

然而,我有很多输入,因此决定提取一个UserControl来封装标签和文本框。问题是,这样做后,我无法再获取文本框来指示错误,我将获取整个控件周围的默认红色框

我尝试了一些建议,比如让孩子控件实现INotifyDataError,但到目前为止我没有运气。这篇文章是同一个问题,我无法找到一个解决方案使用它,所以我希望与更多的标签,这可能会引起更多的注意和解决方案

这是我制作的一个小样本,显示了这个问题。如果输入了无效年龄,则顶部输入将文本框样式设置为红色,但底部用户控件的周围只是一个红色框

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:ValidatorTest" mc:Ignorable="d" x:Class="ValidatorTest.MainWindow"
    Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Window.Resources>
    <ResourceDictionary>

        <CollectionViewSource x:Key="customerViewSource" d:DesignSource="{d:DesignInstance {x:Type local:Customer}, CreateList=True}"/>

        <Style TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="true" >
                    <Setter Property="Foreground" Value="Red"/>
                    <Setter Property="Background" Value="MistyRose"/>
                    <Setter Property="BorderBrush" Value="Red"/>
                    <Setter Property="BorderThickness" Value="1.0"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ResourceDictionary>
</Window.Resources>
<Grid DataContext="{StaticResource customerViewSource}">
    <Grid x:Name="grid1" HorizontalAlignment="Left" Margin="19,27,0,0" VerticalAlignment="Top">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" Orientation="Horizontal">
        <Label Content="Age:" HorizontalAlignment="Left" Margin="3"  VerticalAlignment="Center"/>
        <TextBox x:Name="ageTextBox" HorizontalAlignment="Left" Height="23" Margin="3"
                 Text="{Binding Age, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}" 
                 VerticalAlignment="Center" 
                 Width="120"
                 />
        </StackPanel>
        <local:UnitInput Grid.Row="1"
                         Label="Age"
                         Value="{Binding Age, Mode=TwoWay, ValidatesOnExceptions=True}"/>
    </Grid>
</Grid>

//
///MainWindow.xaml的交互逻辑
/// 
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
}
已加载私有无效窗口(对象发送器、路由目标)
{
CollectionViewSource customerViewSource=((CollectionViewSource)(this.FindResource(“customerViewSource”));
customerViewSource.Source=new[]{new Customer{
年龄=26}};
}
}
使用System.ComponentModel.DataAnnotations;
公共类客户:模型库
{
私人双倍年龄;
[射程(21,55)]
[必需(ErrorMessage=“年龄是必需的。”)]
公众双倍年龄
{
得到
{
返回这个年龄;
}
设置
{
this.ValidateProperty(()=>this.Age,value);
如果(!double.Equals(value,this.age))
{
年龄=价值;
this.raiseProperty已更改(()=>this.Age);
}
}
}
}

//
///UnitInput.xaml的交互逻辑
/// 
公共部分类UnitInput:UserControl
{
公共单位输入()
{
this.InitializeComponent();
}
公共字符串标签
{
得到
{
返回(字符串)GetValue(LabelProperty);
}
设置
{
SetValue(LabelProperty,value);
}
}
//使用DependencyProperty作为标签的后备存储。这将启用动画、样式、绑定等。。。
公共静态只读DependencyProperty LabelProperty=
DependencyProperty.Register(“标签”)、typeof(字符串)、typeof(UnitInput)、new PropertyMetadata(“标签”);
公共字符串值
{
得到
{
返回(字符串)GetValue(ValueProperty);
}
设置
{
设置值(ValueProperty,value);
}
}
//使用DependencyProperty作为值的后备存储。这将启用动画、样式、绑定等。。。
公共静态只读从属属性ValueProperty=
Register(“Value”、typeof(string)、typeof(UnitInput)、newpropertyMetadata(null));
}

提前感谢您的建议。

我没有时间在新项目中设置您的所有代码,但我确实注意到了一个潜在的问题。尝试更改
单元输入
控件中的
绑定
s:

<UserControl x:Class="ValidatorTest.UnitInput"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" >
    <Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UnitInput}}}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0" HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding Label}" VerticalAlignment="Center" Width="100"/>
        <TextBox Grid.Column="1" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="{Binding Value, Mode=TwoWay}" HorizontalContentAlignment="Right" VerticalAlignment="Top" Width="80" Margin="5"/>
    </Grid>
</UserControl>

区别在于这一行:

<Grid DataContext="{Binding RelativeSource={RelativeSource 
    AncestorType={x:Type UnitInput}}}">

要使用的正确的
AncestorType
值是
UserControl
UnitInput
)的名称/类型,而不是标准的
UserControl
,因为其中没有声明
标签或
属性。在VisualStudio的“输出”窗口中会出现一个类似于下面的错误,当您遇到数据绑定问题时,应该首先查看该窗口

System.Windows.Data错误:40:BindingExpression路径错误:在“对象”“用户控件”(HashCode=55649279)上找不到“标签”属性。BindingExpression:Path=Label


请注意,您可能还有更多错误。。。这只是我第一次看到。

谢谢你的建议,但我没有收到这个错误,如果它不正确,那么我不相信我会看到它们所绑定的值,我确实看到了。话虽如此,我同意最好是明确的,所以我做出了改变。谢谢
<UserControl x:Class="ValidatorTest.UnitInput"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" >
    <Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UnitInput}}}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0" HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding Label}" VerticalAlignment="Center" Width="100"/>
        <TextBox Grid.Column="1" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="{Binding Value, Mode=TwoWay}" HorizontalContentAlignment="Right" VerticalAlignment="Top" Width="80" Margin="5"/>
    </Grid>
</UserControl>
<Grid DataContext="{Binding RelativeSource={RelativeSource 
    AncestorType={x:Type UnitInput}}}">