Validation.ErrorTemplate未显示

时间:2014-07-30 13:24:11

标签: wpf validation mvvm user-controls

我有一个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被清除时,应出现默认值。

3 个答案:

答案 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>