I have an issue very similar to these:
Issue with WPF validation(IDataErrorInfo) and tab focusing
TextBox with validation loses ErrorTemplate on tab change
AdornerDecorator
do the trick within the same instance of the Window
, but when the Window
is reloaded and I switch to the TabItem
containing the TextBox
in error, the ErrorTemplate
won't show up anymore.
<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>
...
I tried to retrigger the validation in the code-behind on TabControl
SelectionChanged
, didn't work.
Any idea?
Putting together the pieces of the puzzle
An AdornerLayer represents a surface for rendering adorners. As an
AdornerLayer
usually serves an entire view, not just one control, some containers implement them by default.An adorner is a custom
FrameworkElement
that is bound to aUIElement
. Adorners are rendered in anAdornerLayer
, which is a rendering surface that is always on top of the adorned element or a collection of adorned elements.So in this case the adorner (red rectangle) is bound to a
TextBox
, but is rendered in a layer on top of theTextBox
.Adorning (e.g. in case of a validation error) is done by calling the static method
GetAdornerLayer
to get anAdornerLayer
object for theUIElement
to be adorned.Enough theory
Changing
TabItems
discards theAdornerLayer
, resulting in the adorner not being drawn. 2 fixes:\The manual way, as proposed by DRapp:
Of course, if there's another container implementing an
AdornerLayer
between theAdornerDecorator
and theTextBox
(in the visual tree), this won't do any good. So the explicitAdornerDecorator
needs to be the last one wrapping theTextBox
.\Second solution (which I prefer) resetting the ErrorTemplate each time the
TextBox
becomes visible. In doing so the lack ofAdornerLayer
gets spotted and fixed.