WPF TextBox с проверкой теряет ErrorTemplate

У меня есть проблема, очень похожая на эти:

Проблема с проверкой WPF (IDataErrorInfo) и фокусировкой вкладок

TextBox с проверкой теряет 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>

...

Я попытался повторить проверку в коде на TabControlSelectionChangedне работал.

Любая идея?

2 ответа

Решение

Собираем кусочки головоломки

AdornerLayer представляет поверхность для рендеринга украшений. Как AdornerLayer обычно служит целому представлению, а не одному элементу управления, некоторые контейнеры реализуют их по умолчанию.

Adorner это обычай FrameworkElement это связано с UIElement, Украшения оказываются в AdornerLayer, которая представляет собой поверхность рендеринга, которая всегда находится над украшенным элементом или набором украшенных элементов.

Таким образом, в этом случае рекламодатель (красный прямоугольник) связан с TextBox, но отображается в слое поверх TextBox,

Украшение (например, в случае ошибки проверки) выполняется путем вызова статического метода GetAdornerLayer чтобы получить AdornerLayer объект для UIElement быть украшенным.

Достаточно теории

изменения TabItems отбрасывает AdornerLayer, в результате чего рекламодатель не рисуется. 2 исправления:

\ Ручной способ, предложенный DRapp:

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

Конечно, если есть другой контейнер, реализующий AdornerLayer между AdornerDecorator и TextBox (в визуальном дереве), это не поможет. Так явное AdornerDecorator должен быть последним, оборачивая TextBox,

<XAML for MyView1>
    <Grid>

        ...

        <GroupBox>
            <AdornerDecorator>
                <Grid>

                    ...

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

Второе решение (которое я предпочитаю) сбрасывать ErrorTemplate каждый раз, когда TextBox становится видимым При этом отсутствие 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>

Я видел некоторые странные вещи с WPF и предложил бы это предложение. В соответствии с другими публикациями, на которые вы ссылались и пытались применить их здесь, оборачивая свой вид декоратором adorner, перенесите обтекатель adorner прямо на свою XAML-страницу "MvView1".

Из вашего существующего...

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

изменить на...

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

И в

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

Я заметил подобное, например, применение видимости элементов управления, что если некоторые вещи на одном уровне не работают, на другом - нет. Никогда не нашел точный образец, хотя.

Другие вопросы по тегам