更改选项卡时 WPF 验证停止工作

问题描述 投票:0回答:3

我有一个 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>
c# wpf validation data-binding
3个回答
3
投票

出现此行为的原因是

TabControl
显示其内容的方式:所有选项卡共享相同的
ContentPresenter
。在选项卡之间导航时,旧内容将被完全删除。对于渲染错误模板的
AdornerLayer
也是如此。何 选项卡内容被删除,然后呈现验证错误模板的
Adorner
也被删除。由于
AdornerLayer
是无状态的,并且
TabControl
不监控所有可能的装饰器,因此无法恢复之前选项卡内容的旧渲染错误模板。

您有三个不错的选择:

  1. 不允许用户离开选项卡,除非选项卡的数据处于有效状态或
  2. 离开选项卡时丢弃无效数据(这也会重置相关错误)或
  3. 切换回保存无效数据输入的
    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>

1
投票

为每个 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>

-1
投票

不确定,但试试这个:

string text = txtName.Text;
txtName.Text = null;
txtName.Text = text;
© www.soinside.com 2019 - 2024. All rights reserved.