具有验证的WPF文本框会丢失ErrorTemplate

CTZ*_*tef 5 validation wpf textbox tabcontrol adornerdecorator

我有一个非常类似于这些的问题:

WPF验证(IDataErrorInfo)和标签页焦点问题

具有验证的文本框在选项卡更改时丢失ErrorTemplate

AdornerDecorator这样的伎俩同一个实例内Window,但是当Window被重载,我切换到TabItem包含TextBox错误时,ErrorTemplate 会显示不出来了

<Window x:Class="Views.MyWindowView">
    <Grid>

        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <TabControl HorizontalAlignment="Stretch" 
                    Height="Auto"
                    VerticalAlignment="Top"
                    Width="Auto"
                    SelectionChanged="TabItemChanged"
                    Name="MyTabControl">

            <!-- Below, AdornerDecorator are added for the following reason:
                 the Validation.Error cues are painted in the Adorner Layer. 
                 When tabs are switched, that layer is discarded. -->

            <!-- The view 1 tab.-->
            <TabItem Header="{Resx tab1_Header}"
                     Name="Tbi1">
                <AdornerDecorator>
                    <vw:MyView1 DataContext="{Binding}"/>
                </AdornerDecorator>
            </TabItem>

            <!-- The view 2 tab.-->
            <TabItem Header="{Resx tab2_Header}"
                     Name="Tbi2">
                <AdornerDecorator>
                    <vw:MyView2 DataContext="{Binding}"/>
                </AdornerDecorator>
            </TabItem>
        </TabControl>
Run Code Online (Sandbox Code Playgroud)

...

我尝试在后面的代码中重新触发验证TabControl SelectionChanged,但无效。

任何的想法?

Fun*_*unk 6

拼凑拼图的各个部分

一个AdornerLayer表示用于呈现装饰器的表面。由于AdornerLayer通常服务于整个视图,而不仅仅是一个控件,一些容器默认实现它们。

一个装饰器是一个自定义FrameworkElement绑定到一个UIElement。装饰器在 中渲染AdornerLayer,这是一个始终位于装饰元素或装饰元素集合之上的渲染表面。

因此,在这种情况下,装饰器(红色矩形)绑定到TextBox,但呈现在TextBox.

装饰(例如,在验证错误的情况下)是通过调用静态方法GetAdornerLayer获取要装饰的AdornerLayer对象来完成的UIElement

足够的理论

更改TabItems会丢弃AdornerLayer,导致不会绘制装饰器。2个修复:

\DRapp 提出的手动方式:

<XAML for MyView1>
   <AdornerDecorator>
      ...
   </AdornerDecorator>
</close XAML for MyView1>
Run Code Online (Sandbox Code Playgroud)

当然,如果有另一个容器在( 在可视化树中)和( 在 )AdornerLayer之间实现了,这不会有任何好处。因此,显式需要是包装.AdornerDecoratorTextBoxAdornerDecoratorTextBox

<XAML for MyView1>
    <Grid>

        ...

        <GroupBox>
            <AdornerDecorator>
                <Grid>

                    ...

                    <TextBox ... />
                </Grid>
            </AdornerDecorator>
        </GroupBox>
    </Grid>
</close XAML for MyView1>
Run Code Online (Sandbox Code Playgroud)

\第二个解决方案(我更喜欢)在每次变得可见时重置ErrorTemplateTextBox。在这样做时,缺乏AdornerLayer会被发现和修复。

<UserControl.Resources>
    <Style TargetType="{x:Type TextBox}">
        <Style.Triggers>
            <Trigger Property="IsVisible" Value="true">
                <Setter Property="Validation.ErrorTemplate">
                    <Setter.Value>
                        <ControlTemplate>
                            <Border BorderBrush="Red" BorderThickness="1">
                                <AdornedElementPlaceholder/>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Trigger>
        </Style.Triggers>
    </Style>
</UserControl.Resources>
Run Code Online (Sandbox Code Playgroud)