我有一个MainWindow和一个UserControl。 MainWindow显示UserControl。 UserControl本身遵循MVVM模式并在ViewModel中实现IDataErrorInfo接口。这很好用,但Validation.ErrorTemplate没有显示。
我的UserControl.xaml
<TextBox x:Name="txtName"
Text="{Binding Path=Name, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True}"
Grid.Row="0" Grid.Column="2"
VerticalAlignment="Bottom" MinWidth="100" FontSize="12">
<TextBox.Resources>
<Style TargetType="TextBox">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<StackPanel Orientation="Horizontal">
<AdornedElementPlaceholder>
<Border BorderBrush="Red" BorderThickness="1"/>
</AdornedElementPlaceholder>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Resources>
</TextBox>
ToolTip显示正确,但TextBox的红色边框仅在我使用Snoop并在VisualTree中选择TextBox时显示。
所以我错过了什么?任何触发?
我在两本书中查阅了这个,我尝试了一些正在运行的例子。那么根据UserControl这是一个错误,我必须以某种方式手动更新它吗?
修改 现在,当我以这种方式使用它时,我完全感到困惑:
<TextBox x:Name="txtName"
Text="{Binding Path=Name, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True}"
Grid.Row="0" Grid.Column="2"
VerticalAlignment="Bottom" MinWidth="100" FontSize="12">
<TextBox.Resources>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="BorderThickness" Value="3"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Resources>
</TextBox>
BorderBrush和BorderThickness总是&#34; Red&#34; /&#34; 3&#34;!为什么或如何触发将其设置回来? 根据这个: Only false style displaying when using Validation.HasError trigger property WPF 当Validation.HasError被清除时,应出现默认值。
答案 0 :(得分:2)
所以我发现了我的错误,(或至少部分为什么Validation.HasError永远不会重置)我以错误的方式使用了IDataErrorInfo接口。 如果验证通过,我没有返回null或String.Empty。 :(
//Not used in WPF so return value is null
string IDataErrorInfo.Error { get { return null; } }
string IDataErrorInfo.this[string propertyName]
{
get
{
//the wrong way
string error = "false way";
//the right way
string error = null;
//or
string error = String.Empty;
switch (propertyName)
{
case ("name"):
if (string.IsNullOrEmpty(name) || name.Trim() == String.Empty)
{
error = "Enter name";
}
break;
case ("age"):
if (string.IsNullOrEmpty(age) || age.Trim() == String.Empty)
{
error = "Enter age";
}
break;
default:
Debug.Fail("Validation: Unexpected property: " + propertyName);
break;
}
return error;
}
}
修改强> 有时我得到这个错误,没有修剪...
System.Windows.Data错误:17:无法从'(Validation.Errors)'获取'Item []'值(类型'ValidationError')(类型'ReadOnlyObservableCollection`1')。 BindingExpression:路径=(0)[0] .ErrorContent; DataItem ='TextBox'(Name ='txtName'); target元素是'TextBox'(Name ='txtName'); target属性是'ToolTip'(类型'Object')ArgumentOutOfRangeException:'System.ArgumentOutOfRangeException:Das angegebene ArgumentliegtaußerhalbdesgültigenWertebereichs。 参数名称:索引'
答案 1 :(得分:2)
benba,
我意识到这是一篇很老的帖子,你可能已经转向了更大更好的事情,但我想我会为那些发现这一点的人发布答案,因为像我一样,他们正在挣扎有类似的问题。
我遇到了类似的问题。对我来说,答案是将Path =(Validation.Errors)[0] .ErrorContent替换为 路径=(Validation.Errors).CurrentItem.ErrorContent
这摆脱了System.Windows.Data错误:17:无法获得&#39; Item []&#39;来自&#39;(Validation.Errors)&#39;的值(类型&#39; ValidationError&#39;) (键入&#39; ReadOnlyObservableCollection`1&#39;)。您在编辑中向答案报告的错误。此外,请参阅此博客(这给了我这个想法)以获取更多详细信息: http://chrigas.blogspot.com/2014/05/prevent-systemwindowsdata-error-in.html
干杯,
戴夫
答案 2 :(得分:0)
我认为您需要在Border
周围移动AdornedElementPlaceholder
。这是我使用的ValidationTemplate,它有一个切角,当你将鼠标悬停在它上面时会显示错误信息。
<ControlTemplate x:Key="ErrorTemplate">
<StackPanel>
<!--TextBox Error template-->
<Canvas Panel.ZIndex="1099">
<DockPanel>
<Border BorderThickness="1" BorderBrush="#FFdc000c" CornerRadius="0.7"
VerticalAlignment="Top" DockPanel.Dock="Bottom" HorizontalAlignment="Left">
<Grid>
<Polygon x:Name="toolTipCorner"
Grid.ZIndex="2"
Margin="-1"
Points="11,11 11,0 0,0"
Fill="#FFdc000c"
HorizontalAlignment="Right"
VerticalAlignment="Top"
IsHitTestVisible="True"/>
<Polyline Grid.ZIndex="3"
Points="12,12 0,0" Margin="-1" HorizontalAlignment="Right"
StrokeThickness="1.5"
StrokeEndLineCap="Round"
StrokeStartLineCap="Round"
Stroke="White"
VerticalAlignment="Top"
IsHitTestVisible="True"/>
<AdornedElementPlaceholder x:Name="ErrorAdorner" />
</Grid>
</Border>
</DockPanel>
<Popup x:Name="ErrorPopup" Opacity="0" IsOpen="False" AllowsTransparency="True" Placement="Bottom" PlacementTarget="{Binding ElementName=ErrorAdorner}" StaysOpen="True">
<Border Canvas.Bottom="4"
x:Name="errorBorder"
Canvas.Left="{Binding Path=AdornedElement.ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Adorner}}"
CornerRadius="5"
Background="#FFdc000c">
<Border.Effect>
<DropShadowEffect ShadowDepth="2.25"
Color="Black"
Opacity="0.4"
Direction="315"
BlurRadius="4"/>
</Border.Effect>
<TextBlock TextWrapping="Wrap" Margin="4"
MaxWidth="250" Foreground="White"
FontSize="12"
Text="{Binding Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Adorner}}" />
</Border>
</Popup>
</Canvas>
</StackPanel>
<ControlTemplate.Triggers>
<DataTrigger Value="True" Binding="{Binding ElementName=toolTipCorner, Path=IsMouseOver}">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="fadeInStoryboard">
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="ErrorPopup"
Storyboard.TargetProperty="IsOpen">
<DiscreteBooleanKeyFrame Value="True" KeyTime="00:00:00"/>
</BooleanAnimationUsingKeyFrames>
<DoubleAnimation Duration="00:00:00.15"
Storyboard.TargetName="errorBorder"
Storyboard.TargetProperty="Opacity"
To="1"/>
<ThicknessAnimation Duration="00:00:00.15"
Storyboard.TargetName="errorBorder"
Storyboard.TargetProperty="Margin"
FillBehavior="HoldEnd"
From="1,0,0,0"
To="5,0,0,0">
<ThicknessAnimation.EasingFunction>
<BackEase EasingMode="EaseOut" Amplitude="2"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="fadeInStoryboard"/>
<BeginStoryboard x:Name="fadeOutStoryBoard">
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="ErrorPopup"
Storyboard.TargetProperty="IsOpen">
<DiscreteBooleanKeyFrame Value="False" KeyTime="00:00:00"></DiscreteBooleanKeyFrame>
</BooleanAnimationUsingKeyFrames>
<DoubleAnimation Duration="00:00:00"
Storyboard.TargetName="errorBorder"
Storyboard.TargetProperty="Opacity"
To="0"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
然后,您可以将此项设置为ErrorTemplate
,如下所示:
<Style TargetType="TextBox">
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ErrorTemplate2}"/>
</Style>