WPF Error Styles only being rendered properly on visible tab of a tab control

假装没事ソ 提交于 2019-11-29 21:50:24
Steffen Opel

(I am using the AdornerDecorator as I had experienced in a previous program the error style not being re-rendered when swapping tab pages. I can't remember where I saw this but it did help me out)

Presumably this indeed important tip originates from Karl Shifflets blog, at least he's addressing the same topic: WPF Validation Errors Disappear Inside TabControl When Switching TabItems.

Given this your issue might just be related, i.e. the tip/code above ensures there is a dedicated AdornerLayer for every tab item now, as the adorner layer of the parent element is discarded when you switch tabs. This dedicated adorner layer appears to still require some special treatment though, see for example question WPF ErrorTemplate visible when not focused? which is basically dealing with your issue upside down. Consequently I'd suggest you combine and expand the outlined solution for the latter with your style and try the following (untested code as of now though):

<Style x:Key="ErrorTemplate" TargetType="{x:Type TextBox}">
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="True">...</Trigger>
        <Trigger Property="IsVisible" Value="false">
            <Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
        </Trigger>
        <Trigger Property="IsVisible" Value="true">
            <Setter Property="Validation.ErrorTemplate">
                <Setter.Value>...</Setter.Value>
            </Setter>
        </Trigger>
    </Style.Triggers>
</Style>

See my comment regarding your update of Radio Button Error Style too, which tries to similarly address your likely related question; have you actually tried my suggestion there?

See Adorners Overview for more details on the adorner architecture.

Steffen Opel solved my problem with his link : WPF Validation Errors Disappear Inside TabControl When Switching TabItems.

<TabControl>

  <TabItem>
    <AdornerDecorator>
      <StackPanel>
        ...
      </StackPanel>
    </AdornerDecorator>
  </TabItem>

  <TabItem>
    <AdornerDecorator>
      <StackPanel>
        ...
      </StackPanel>
    </AdornerDecorator>
  </TabItem>

  <TabItem>
    <AdornerDecorator>
      <StackPanel>
        ...
      </StackPanel>
    </AdornerDecorator>
  </TabItem>

</TabControl>
MoonStom

Just to add to the answer provided, the error template can be set once in a resource dictionary. Just the triggers have to be copied & pasted for all the default styles of all the relevant element types.

For example:

<ResourceDictionary ...>
    <!-- Add to the default style instead of replacing it -->
    <Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
        <Style.Triggers>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="Validation.HasError" Value="True" />
                    <Condition Property="IsVisible" Value="True" />
                </MultiTrigger.Conditions>
                <Setter Property="Validation.ErrorTemplate" Value="{DynamicResource ValidationErrorTemplate}"/>
            </MultiTrigger>
        </Style.Triggers>
    </Style>

    <Style TargetType="PasswordBox" BasedOn="{StaticResource {x:Type PasswordBox}}">
        <Style.Triggers>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="Validation.HasError" Value="True" />
                    <Condition Property="IsVisible" Value="True" />
                </MultiTrigger.Conditions>
                <Setter Property="Validation.ErrorTemplate" Value="{DynamicResource ValidationErrorTemplate}"/>
            </MultiTrigger>
        </Style.Triggers>
    </Style>
</ResourceDictionary>

Or, take it one step further and avoid the trigger repetition by combining the styles:

<ResourceDictionary ...>
    <Style x:Key="ErrorControlStyle" TargetType="Control">
        <Style.Triggers>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="Validation.HasError" Value="True" />
                    <Condition Property="IsVisible" Value="True" />
                </MultiTrigger.Conditions>
                <Setter Property="Validation.ErrorTemplate" Value="{DynamicResource ValidationErrorTemplate}"/>
            </MultiTrigger>
        </Style.Triggers>
    </Style>

    <Style TargetType="PasswordBox" BasedOn="{extensions:MultiStyle . ErrorControlStyle}"/>
    <Style TargetType="TextBox" BasedOn="{extensions:MultiStyle . ErrorControlStyle}"/>
</ResourceDictionary>

but I'd stay away from this approach as it will break the designer.

In the examples above I used the template named ValidationErrorTemplate from MahApps.Metro

Also, don't forget to also use the AdornerDecorator inside the TabItem fix, as described by @Abyte0, in order to maintain the validations when tab switching.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!