WPF TextBox Border Style Trigger IsFocused only works if has focus but not keyboard focus

triggerswpfwpf-stylexaml

I would like a nice little orange border around my Textbox whilst the user is typing in it (Has Focus).

I defined styles for the tiggers I think I need, but there is a strange behavior.

When the cursor is in the TextBox and the WPF app has focus, it has a blue border.

But while the cursor is focused and I click outside of the app (like in visual studio) it becomes orange.

I've tried overriding many triggers but to no avail.

This is what happens when I focus on the textbox but am focused on another app:

Focus but outside of app

This is the textbox w/focus in the app:

Focused in the app

And here is the code:

CTRL Xaml:

   <TextBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" 
                                         Style="{StaticResource RegistrationTextbox}" 
                                         IsReadOnly="{Binding Path=IsFirstNameReadOnly}" Text="{Binding FirstName}"  BorderThickness="0.99">
                                        <b:Interaction.Triggers>
                                            <b:EventTrigger EventName="GotFocus">
                                                <b:InvokeCommandAction Command="{Binding GotFocusFirstNameCommand}" />
                                            </b:EventTrigger>
                                        </b:Interaction.Triggers>
                                    </TextBox>

Styles:

  <Style x:Key="RegistrationTextbox" TargetType="{x:Type TextBox}">
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>

    <Style.Triggers>
        <Trigger Property="IsReadOnly" Value="true">
            <Setter Property="Background" Value="#f2f2f2"/>
            <Setter Property="BorderBrush" Value="#f2f2f2"/>
            <Setter Property="BorderThickness" Value="2"/>
        </Trigger>
        <Trigger Property="IsKeyboardFocused" Value="true">
            <Setter Property="BorderBrush" Value="Red"/>
            <Setter Property="BorderThickness" Value="2"/>
        </Trigger>
        <Trigger Property="IsFocused"  Value="True">
            <Setter Property="BorderBrush" Value="#FAA634"/>
            <Setter Property="BorderThickness" Value="2"/>
        </Trigger>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="BorderBrush" Value="#F8B963"/>
            <Setter Property="BorderThickness" Value="2"/>
        </Trigger>
    </Style.Triggers>        
</Style>

Best Answer

Take a look at default TextBox style here: https://msdn.microsoft.com/en-us/library/cc645061%28v=vs.95%29.aspx

You will notice that in ControlTemplate there is this block:

     <Border x:Name="Border" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="1" Opacity="1" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}">
     <Grid>
           <Border x:Name="ReadOnlyVisualElement" Opacity="0" Background="#5EC9C9C9"/>
           <Border x:Name="MouseOverBorder" BorderThickness="1" BorderBrush="Transparent">
               <ScrollViewer x:Name="ContentElement" Padding="{TemplateBinding Padding}" BorderThickness="0" IsTabStop="False"/>
           </Border>
     </Grid>
     </Border>
     <Border x:Name="DisabledVisualElement" Background="#A5F7F7F7" BorderBrush="#A5F7F7F7" BorderThickness="{TemplateBinding BorderThickness}" Opacity="0" IsHitTestVisible="False"/>
     <Border x:Name="FocusVisualElement" BorderBrush="#FF6DBDD1" BorderThickness="{TemplateBinding BorderThickness}" Margin="1" Opacity="0" IsHitTestVisible="False"/>

You see here that only one Border's BorderBrush is bound to BorderBrush property of TextBox. When control goes to focused state - another border (FocusVisualElement) becomes visible and because it's positined later in visual tree - it overlays regular Border. Same is true when control goes to disabled or readonly state. So your style setters basically have no effect.

Now when your are switching to another app - TextBox does not consider it focused any more (note that it does not just use IsFocused property to determine that). So it hides FocusVisualElement and here you see border color applied by your trigger.

Long story short - control developers are not forced to bind to single BorderBrush property for every possible state. They could have provided something like FocusedBorderBrush property, but they did not - so you have to overwrite ControlTemplate of TextBox (you can use default template as provided by link above and overwrite some colors).

Related Topic