16

我正在尝试使用该IDataErrorInfo接口在我的 WPF 应用程序中实现验证,但我遇到了一个不太理想的情况。

我有这个模板,当控件无法验证时使用

<ControlTemplate x:Key="errorTemplate">
    <DockPanel LastChildFill="true">
        <Border Background="Red" DockPanel.Dock="Right" Margin="5,0,0,0" Width="20" Height="20" CornerRadius="10"
                                    ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
            <TextBlock Text="!" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold" Foreground="White" />
        </Border>
        <AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center" >
            <Border BorderBrush="red" BorderThickness="1" />
        </AdornedElementPlaceholder>
    </DockPanel>
</ControlTemplate>

一切都很好,直到我尝试在未通过验证的控件上方显示某些内容,例如在其上方显示停靠项:

正常显示 部分控件隐藏时显示

我怎样才能避免这种情况并让我的错误模板显示在停靠项下方,因为它应该?

编辑

我发现我可以TextBox用 anAdornerDecorator来解决这个问题,但我真的不想为TextBox我的应用程序中的每个控件都这样做。有没有办法用aStyle或其他方式设置它?

编辑 2

我可能会更改默认TextBoxControlTemplate 以包含AdornerDecorator,但我不太热衷于更改 WPF 的任何默认控件模板。欢迎任何其他建议。

4

3 回答 3

14

好的,我找到了一个相对简单的解决方案,它不会强迫我更改任何控件模板。

TextBox而不是AdornerDecorator像这样装饰每个

<StackPanel>
    <AdornerDecorator>
        <TextBox Text={Binding ...} />
    </AdornerDecorator>
    <AdornerDecorator>
        <TextBox Text={Binding ...} />
    </AdornerDecorator>
</StackPanel>

我可以AdornerDecorator将整个视图包裹起来,从而达到相同的效果。

<AdornerDecorator>
    <StackPanel>
        <TextBox Text={Binding ...} />
        <TextBox Text={Binding ...} />
    </StackPanel>
</AdornerDecorator>

这样我可以在每个视图中最多定义一次。

于 2012-04-24T10:11:02.190 回答
3

基于@AdiLester 很好的答案,如果您的控件是从基类派生的,并且您不想放入AdornerDecorator每个控件的 XAML,那么请这样:

public class MyBaseUserControl : UserControl
{
    public MyBaseUserControl()
    {

    }

    protected override void OnContentChanged(object oldContent, object newContent)
    {
        base.OnContentChanged(oldContent, newContent);

        if (!(newContent is AdornerDecorator))
        {
            this.RemoveLogicalChild(newContent);

            var decorator = new AdornerDecorator();
            decorator.Child = newContent as UIElement;

            this.Content = decorator;
        }
    }
}
于 2014-12-02T07:03:23.217 回答
0

我会使用一种风格,这里有一个你可以轻松适应的例子。

请注意,ErrorContent 来自 (Validation.Errors).CurrentItem.ErrorContent,而不是 Errors[0]。虽然两者都可以工作,但后者会在您的输出窗口中乱扔吞咽异常,如此处所述

<Style x:Key="TextBoxStyle" TargetType="{x:Type TextBox}">
    <Setter Property="Margin" Value="0,0,16,0" />
    <Setter Property="VerticalAlignment" Value="Center" />
    <Setter Property="VerticalContentAlignment" Value="Center" />

    <!--
    Error handling
    -->
    <Setter Property="Validation.ErrorTemplate">
        <Setter.Value>
            <ControlTemplate>
                <DockPanel LastChildFill="True">
                    <TextBlock DockPanel.Dock="Right" Text=" *" 
                               Foreground="Red" FontWeight="Bold" FontSize="16" 
                               ToolTip="{Binding ElementName=placeholder, Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent}"/>
                    <Border BorderBrush="Red"  BorderThickness="1">
                        <AdornedElementPlaceholder Name="placeholder"></AdornedElementPlaceholder>
                    </Border>
                </DockPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="True">
            <Setter Property="Background" Value="LightYellow"/>
        </Trigger>
    </Style.Triggers>
</Style>
于 2012-04-24T10:05:12.293 回答