WPF带验证的文本框丢失了ErrorTemplate。

5

我遇到了类似以下问题:

WPF验证(IDataErrorInfo)和Tab焦点的问题

具有验证的TextBox在Tab更改时失去ErrorTemplate

AdornerDecorator可以在同一实例的Window中解决这个问题,但当Window重新加载并切换到包含错误TextBoxTabItem时,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>

我尝试在代码后端的TabControl SelectionChanged上重新触发验证,但没有成功。

有什么想法吗?


1
那是一个模态对话框窗口。它可以被打开和关闭多次。这就是我所说的“重新加载”的意思。 - CTZStef
你是在隐藏它并显示它,而不是在中间销毁它吗? - user1228
每次都是一个新的实例;即被销毁。请注意,当我在xaml中切换选项卡时,ErrorTemplate会在运行时显示在TextBox上。只有当我必须导航到TabItem时,它才不起作用。 - CTZStef
1
IDataErrorInfo属性已经被检查。实际上,很奇怪的是,像@Funk建议的那样将TextBox包装在AdornerDecorator中就解决了问题。 - CTZStef
1
干得好!这些问题很难追踪和修复。 - user1228
显示剩余2条评论
2个回答

6

拼凑谜题

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

Adorner 是一个绑定到 UIElement 的自定义 FrameworkElement。Adorners 在 AdornerLayer 中呈现,该层是放置在被装饰元素或一组被装饰元素的顶部的呈现表面。

因此,在这种情况下,装饰元素(红色矩形)绑定到 TextBox,但在 TextBox 的顶部渲染图层中呈现。

通过调用静态方法 GetAdornerLayer 获取要装饰的 UIElementAdornerLayer 对象来创建装饰效果(例如在发生验证错误时)。

足够的理论知识

更改 TabItems 会丢弃 AdornerLayer,导致装饰元素无法呈现。可以通过以下两种方法进行修复:

第一种方法是手动方式,如 DRapp 所建议:

<XAML for MyView1>
   <AdornerDecorator>
      ...
   </AdornerDecorator>
</close XAML for MyView1>

当然,如果在可视树中的AdornerDecoratorTextBox之间有另一个实现AdornerLayer的容器,这将没有任何作用。因此,显式的AdornerDecorator需要是最后一个包装TextBox的容器。
<XAML for MyView1>
    <Grid>

        ...

        <GroupBox>
            <AdornerDecorator>
                <Grid>

                    ...

                    <TextBox ... />
                </Grid>
            </AdornerDecorator>
        </GroupBox>
    </Grid>
</close XAML for MyView1>

\第二种解决方案(我更喜欢的)是每次TextBox可见时重置ErrorTemplate。这样可以发现并修复缺少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>

2

我见过一些与WPF相关的奇怪问题,并提出以下建议。根据您参考并尝试在此处应用的其他帖子,将adorner装饰器与视图包装起来,请将adorner的包装直接移动到您的"MvView1" XAML页面中。

从您现有的...

<AdornerDecorator>
   <vw:MyView1 DataContext="{Binding}"/>
</AdornerDecorator>

转换为...

<vw:MyView1 DataContext="{Binding}"/>

and in

<XAML for MyView1>
   <AdornerDecorator>
      [wrapping is within the view... then the rest of the view...]
   </AdornerDecorator>
</close XAML for MyView1>

我注意到类似的问题,比如控件的可见性,除非某些事情在一个级别上,否则它们可以工作,在另一个级别上则不行。虽然我从未找到确切的模式。


1
@CTZStef 一些控件(例如Groupbox)似乎会破坏流程并需要将AdornerDecorator放置在其中。作为快速检查,请尝试包装TextBox - Funk
@Funk包装TextBox在AdornerDecorator中可以解决问题;请创建一个答案,我很乐意接受它。如果您还能添加一些关于这个神奇操作的细节,那就太好了。谢谢! - CTZStef

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接