Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does TextBox Border Colour insist on and not changing in WPF?

As far as I understand I should be using Style triggers to update the TextBox's border colour when it is focused. However no matter what I do it always turns to the system default blue, not the black I have specified.

Anyone have any ideas?

Code below:

<UserControl.Resources>
    <Style TargetType="TextBox">
        <Style.Triggers>
            <Trigger Property="IsFocused" Value="True">
                <Setter Property="BorderBrush" Value="Black" />
            </Trigger>
        </Style.Triggers>
    </Style>
</UserControl.Resources>
like image 969
dannybrown Avatar asked Feb 15 '14 13:02

dannybrown


2 Answers

Try set for BorderThickness value more than 1 (by default):

<Window.Resources>
    <Style TargetType="{x:Type TextBox}">
        <Style.Triggers>
            <Trigger Property="IsFocused" Value="True">
                <Setter Property="BorderBrush" Value="Pink" />
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>

<Grid>
    <TextBox Width="100"
             Height="30"
             Text="Test" 
             BorderThickness="4" />
</Grid>

Tested on Windows Seven.

Edit: why is this happening?

I looked in the default style for TextBox in Blend under Windows 7, here it is ControlTemplate:

<ControlTemplate x:Key="TextBoxControlTemplate1" TargetType="{x:Type TextBox}">
    <Microsoft_Windows_Themes:ListBoxChrome x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" SnapsToDevicePixels="true">
        <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
    </Microsoft_Windows_Themes:ListBoxChrome>

    <ControlTemplate.Triggers>
        <Trigger Property="IsEnabled" Value="false">
            <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

Here there is two parameters:

RenderMouseOver="{TemplateBinding IsMouseOver}"
RenderFocused="{TemplateBinding IsKeyboardFocusWithin}"

They are responsible for blue gradient Border when states Focus and MouseOver and probably there stands a condition on BorderThickness and BorderBrush. If they remove / reset the blue gradient Border will disappear and will not need to set values for BorderThickness greater than 1.

In ILSpy I found ChangeVisualState(bool) method in TextBoxBase class, here it is:

internal override void ChangeVisualState(bool useTransitions)
{
    if (!base.IsEnabled)
    {
        VisualStateManager.GoToState(this, "Disabled", useTransitions);
    }
    else
    {
        if (this.IsReadOnly)
        {
            VisualStateManager.GoToState(this, "ReadOnly", useTransitions);
        }
        else
        {
            if (base.IsMouseOver)
            {
                VisualStateManager.GoToState(this, "MouseOver", useTransitions);
            }
            else
            {
                VisualStateManager.GoToState(this, "Normal", useTransitions);
            }
        }
    }

    if (base.IsKeyboardFocused)
    {
        VisualStateManager.GoToState(this, "Focused", useTransitions);
    }
    else
    {
        VisualStateManager.GoToState(this, "Unfocused", useTransitions);
    }

    base.ChangeVisualState(useTransitions);
}

It turns out that these visual states implemented "systematically" and in Styles not present.

like image 67
Anatoliy Nikolaev Avatar answered Nov 06 '22 22:11

Anatoliy Nikolaev


Default template of TextBox has trigger which set the border brush of textBox. In case you want to override it, you need to override ControlTemplate of TextBox.

This is how you do that:

<Style TargetType="TextBox">
    <Setter Property="Template">
       <Setter.Value>
          <ControlTemplate TargetType="TextBox">
              <Border BorderThickness="{TemplateBinding Border.BorderThickness}"
                      BorderBrush="{TemplateBinding Border.BorderBrush}"
                      Background="{TemplateBinding Panel.Background}"
                      Name="border"
                      SnapsToDevicePixels="True">
                 <ScrollViewer HorizontalScrollBarVisibility="Hidden"
                               VerticalScrollBarVisibility="Hidden"
                               Name="PART_ContentHost"
                               Focusable="False" />
              </Border>
           <ControlTemplate.Triggers>
              <Trigger Property="UIElement.IsEnabled" Value="False">
                <Setter Property="UIElement.Opacity" TargetName="border"
                        Value="0.56"/>
              </Trigger>
              <Trigger Property="UIElement.IsMouseOver" Value="True">
                <Setter Property="Border.BorderBrush" TargetName="border" 
                        Value="#FF7EB4EA"/>
              </Trigger>
              <Trigger Property="UIElement.IsKeyboardFocused" Value="True">
                <Setter Property="Border.BorderBrush" TargetName="border" 
                       Value="Black"/> <-- HERE
              </Trigger>
           </ControlTemplate.Triggers>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
 </Style>

Also you might want to override MouseOver brush to Black in above template. You can do that by supplying color value for UIElement.IsMouseOver trigger.

like image 22
Rohit Vats Avatar answered Nov 06 '22 23:11

Rohit Vats