【问题标题】:WPF validation stops working when changing tabs更改选项卡时 WPF 验证停止工作
【发布时间】:2020-08-17 19:06:19
【问题描述】:

我有一个 WPF 应用程序,其中有一个 TabControl,并且在某个选项卡内有一个带有验证规则的 TextBox

验证规则工作正常,转换器工作正常,绑定也正常。
但是当我这样做时会发生一个非常烦人的错误(可能与 WPF 本身有关):

  • 输入无效文本(验证发生,文本框出现红色边框)
  • 切换到另一个标签
  • 返回带有文本框的选项卡。

验证完全停止工作,直到我输入 valid 文本,然后它再次开始工作。 更改文本是不够的,只有输入有效文本才会重新开始工作。

当我进入选项卡时如何强制重新验证文本?


我已经尝试了两种解决方案listed here,但似乎没有带红色边框:

  • 在选项卡上的事件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


    【解决方案1】:

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

    你有三个不错的选择:

    1. 不允许用户离开选项卡,除非选项卡的数据处于有效状态或
    2. 离开选项卡时丢弃无效数据(这也会重置相关错误)或
    3. 在切换回包含无效数据输入的TabItem 时强制AdornerLayer 重新渲染。

    以下示例显示了如何强制 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>
    

    【讨论】:

      【解决方案2】:

      不确定,但试试这个:

      string text = txtName.Text;
      txtName.Text = null;
      txtName.Text = text;
      

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-01-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-06-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多