【问题标题】:Error template is displayed above other controls, when it should be hidden错误模板显示在其他控件上方,应隐藏时
【发布时间】:2012-05-04 21:19:08
【问题描述】:

我正在尝试使用 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>

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

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

编辑

我发现我可以用AdornerDecorator 包装我的TextBox 来解决这个问题,但我真的不想为我的应用程序中的每个TextBox 控件执行此操作。有没有办法用Style 或其他方式设置它?

编辑 2

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

【问题讨论】:

    标签: .net wpf validation xaml idataerrorinfo


    【解决方案1】:

    基于@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;
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

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

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

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

      我可以让AdornerDecorator 包裹我的整个视图,这样可以获得相同的结果。

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

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

      【讨论】:

        【解决方案3】:

        我会使用一种样式,这里有一个您可以轻松适应的示例。

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

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

        【讨论】:

        • 我看不出这如何解决任何问题。边框仍显示在停靠项上方。
        猜你喜欢
        • 1970-01-01
        • 2012-07-19
        • 2020-10-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-01
        • 2013-08-07
        • 1970-01-01
        相关资源
        最近更新 更多