我有一个 WPF 应用程序,其中有一个
TabControl
,并且在某个选项卡内有一个带有验证规则的 TextBox
。
验证规则工作正常,转换器工作正常,绑定也正常。
但是当我这样做时会发生一个非常烦人的错误(可能是 WPF 本身):
验证完全停止工作,直到我输入valid文本,然后它再次开始工作。 更改文本是不够的,只有当我输入有效文本时它才会再次开始工作。
如何在进入选项卡时强制重新验证文本?
Selector.Selected
中(检查是否正在调用),添加 txtName.GetBindingExpression(TextBox.TextProperty).UpdateSource();
ValidatesOnTargetUpdated="True"
属性这是 XAML 的简短描述(如果需要):
<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>
出现此行为的原因是
TabControl
显示其内容的方式:所有选项卡共享相同的 ContentPresenter
。在选项卡之间导航时,旧内容将被完全删除。对于渲染错误模板的 AdornerLayer
也是如此。何
选项卡内容被删除,然后呈现验证错误模板的 Adorner
也被删除。由于 AdornerLayer
是无状态的,并且 TabControl
不监控所有可能的装饰器,因此无法恢复之前选项卡内容的旧渲染错误模板。
您有三个不错的选择:
AdornerLayer
时强制 TabItem
重新渲染。以下示例展示了如何在装饰元素可见时强制
AdornerLayer
再次渲染所有 TextBox
元素的装饰器:
<!-- 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>
为每个 TabItem 提供其自己的 AdornerLayer(通过 AdornerDecorator 元素),如下所示。装饰层中的元素将跨选项卡开关进行维护。
<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>
不确定,但试试这个:
string text = txtName.Text;
txtName.Text = null;
txtName.Text = text;