Reputation: 86600
I have a WPF application where there is a TabControl
, and within a certain tab there is a TextBox
with a validation rule.
The validation rule works fine, the converter works fine, the binding is ok too.
But there is a very annoying bug (probably with WPF itself) that happens when I do this:
The validation completely stops working until I type a valid text, then it starts working again. Changing the text is not enough, it will only start working again if I enter a valid text.
How can I force a revalidation of the text when I enter the tab?
Selector.Selected
on the tab (checked that it's being called), add txtName.GetBindingExpression(TextBox.TextProperty).UpdateSource();
ValidatesOnTargetUpdated="True"
property in the validation ruleThis is a brief description of the XAML, if needed:
<TabControl ...>
<TabItem ... />
<TabItem ...>
...
<TextBox Name="txtName" ...>
<TextBox.Text>
<Binding Path="..."
UpdateSourceTrigger="PropertyChanged"
Mode="OneWayToSource"
FallbackValue="5"
Converter="MyCustomConverterWorkingOk">
<Binding.ValidationRules>
<local:MyCustomValidationWorkingOk/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</TabItem>
</TabControl>
Upvotes: 2
Views: 1066
Reputation: 28968
The reason for this behavior is the way the TabControl
displays its content: all tabs share the same ContentPresenter
. When navigating between tabs, the old content is completely removed. This is also true for the AdornerLayer
, on which the error template is rendered.
When the tab content is removed then the Adorner
that renders the validation error template is also removed. Since the AdornerLayer
is stateless and the TabControl
doesn't monitor all the possible adorners, the old rendered error templates of the previous tab content can't be restored.
You have three good options:
AdornerLayer
to re-render when switching back to a TabItem
which holds invalid data input.The following example shows how you can force the AdornerLayer
to render the adorner of all TextBox
elements again as soon as the adorned element is visible:
<!-- Custom error template -->
<ControlTemplate x:Key="ValidationErrorTemplate">
<StackPanel>
<!-- Placeholder for the TextBox itself -->
<AdornedElementPlaceholder />
<TextBlock Text="{Binding ErrorContent}"
Foreground="Red" />
</StackPanel>
</ControlTemplate>
<!-- Style to trigger the rendering of the AdornerLayer by setting the error template -->
<Style TargetType="TextBox">
<Setter Property="Validation.ErrorTemplate"
Value="{x:Null}" />
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Validation.HasError"
Value="True" />
<Condition Property="IsVisible"
Value="True" />
</MultiTrigger.Conditions>
<Setter Property="Validation.ErrorTemplate"
Value="{StaticResource ValidationErrorTemplate}" />
</MultiTrigger>
</Style.Triggers>
</Style>
Upvotes: 3
Reputation: 266
Give each TabItem its own AdornerLayer (via the AdornerDecorator element) as shown below. The elements in the adorner layer will be maintained across tab switches.
<TabItem Header="Tab 1">
<AdornerDecorator>
<Grid Background="WhiteSmoke">
<TextBlock Text="Hello from #1" />
</Grid>
</AdornerDecorator>
</TabItem>
<TabItem Header="Tab 2">
<AdornerDecorator>
<Grid Background="WhiteSmoke">
<TextBlock Text="Hello from #2" />
</Grid>
</AdornerDecorator>
</TabItem>
Upvotes: 1
Reputation: 28
Not sure but try this:
string text = txtName.Text;
txtName.Text = null;
txtName.Text = text;
Upvotes: -1