我已使用DataAnnotations和INotifyDataError在我的应用程序中实现了验证,并且可以成功显示何时发生错误以及错误是什么。我希望更改默认错误模板以设置输入值的文本框的样式。
如果TextBox存在于与创建基础数据模型的绑定相同的UserControl中,则此方法可以正常使用。
但是我有很多输入,因此决定提取UserControl来封装标签和文本框。问题是,完成此操作后,我无法再使用文本框指示错误,我会在整个控件周围显示默认的红色框。
我已经尝试了一些建议,例如让子控件实现INotifyDataError,但到目前为止我没有运气。这篇文章是同一个问题,我找不到使用它的解决方案,所以我希望有更多标签,这可能会引起更多关注和解决方案Show Validation Error in UserControl
这是我制作的一个小样本,显示了问题。如果输入的年龄无效,则顶部条目将TextBox设置为红色,但底部用户控件只有一个红色框。
<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>
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
CollectionViewSource customerViewSource = ((CollectionViewSource)(this.FindResource("customerViewSource")));
customerViewSource.Source = new [] { new Customer{
Age = 26}};
}
}
using System.ComponentModel.DataAnnotations;
public class Customer : ModelBase
{
private double? age;
[Range(21, 55)]
[Required(ErrorMessage = "Age is required.")]
public double? Age
{
get
{
return this.age;
}
set
{
this.ValidateProperty(() => this.Age, value);
if (!double.Equals(value, this.age))
{
this.age = value;
this.RaisePropertyChanged(() => this.Age);
}
}
}
}
<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 UserControl}}}">
<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>
/// <summary>
/// Interaction logic for UnitInput.xaml
/// </summary>
public partial class UnitInput : UserControl
{
public UnitInput()
{
this.InitializeComponent();
}
public string Label
{
get
{
return (string)GetValue(LabelProperty);
}
set
{
SetValue(LabelProperty, value);
}
}
// Using a DependencyProperty as the backing store for Label. This enables animation, styling, binding, etc...
public static readonly DependencyProperty LabelProperty =
DependencyProperty.Register("Label", typeof(string), typeof(UnitInput), new PropertyMetadata("Label"));
public string Value
{
get
{
return (string)GetValue(ValueProperty);
}
set
{
SetValue(ValueProperty, value);
}
}
// Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(string), typeof(UnitInput), new PropertyMetadata(null));
}
提前感谢您的建议。
答案 0 :(得分:0)
我没有时间在新项目中设置所有代码,但我确实注意到了潜在的问题。尝试更改Binding
控件中的UnitInput
:
<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
,因为没有在其中声明Label
或Value
属性。在Visual Studio的输出窗口中,您可能会遇到类似于下面的错误,当您遇到数据绑定问题时,总是是您首先看到的错误。
System.Windows.Data错误:40:BindingExpression路径错误:'object'''UserControl'(HashCode = 55649279)'上找不到'Label'属性。 BindingExpression:路径=标签; ...
请注意,可能还有其他错误......这只是我看到的第一个错误。