Search code examples
c#wpfxamluser-interfacetextbox

I want to display a line on the bottom of a TextBox when its hovered over


So basically I want to achieve a hover-effect and that effect would be a line would appear on the bottom of a textbox, the width of that line must be half the actual width of the TextBox.

If possible, I would like an animation, perhaps a ColorAnimation that would gradually change its color from transparent to solid. I also wanted to specify that my TextBox is a watermarked TextBox.

An example of what I want to achieve is this: EXAMPLE

<Style TargetType="{x:Type local:TextBox}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:TextBox}">
                <DockPanel HorizontalAlignment="Stretch">
                    <Border CornerRadius="10" BorderBrush="{StaticResource BackgroundColor}" BorderThickness="1" Background="{StaticResource BackgroundColor}">
                        <Grid Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActualWidth}">
                            <TextBox Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActualWidth}" VerticalAlignment="Center" Foreground="{StaticResource TextColor}" Background="{StaticResource BackgroundColor}" Padding="10" HorizontalAlignment="Left" x:Name="SearchTermTextBox" Margin="5" BorderThickness="0"/>
                                <TextBlock IsHitTestVisible="False" Text="Enter Search Term Here" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="20,0,0,0" Foreground="{StaticResource TextColor}" Background="{StaticResource BackgroundColor}">
                                    <TextBlock.Style>
                                        <Style TargetType="{x:Type TextBlock}">
                                            <Setter Property="Visibility" Value="Collapsed"/>
                                            <Style.Triggers>
                                                <DataTrigger Binding="{Binding Text, ElementName=SearchTermTextBox}" Value="">
                                                    <Setter Property="Visibility" Value="Visible"/>
                                                </DataTrigger>
                                            </Style.Triggers>
                                        </Style>
                                    </TextBlock.Style>
                                </TextBlock>
                        </Grid>         
                    </Border>
                </DockPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Solution

  • TextBox is a Control so it can be re-templated like any other. The trick is to ensure that there is a child element named PART_ContentHost - which is ordinarily a ScrollViewer - which will be used by the control to render the editable text. (See the WPF Default Styles and Templates documentation for TextBox for more detail).

    Here is a simple example that will display an underline on hover with a 0.25 second fade in/out and will take up 50% of the TextBox's width (thanks to some Grid column logic). You should be able to tweak it further to get the look/behavior you want. And don't forget you can always subclass TextBox to add more DependencyPropertys for additional granularity over the appearance.

    <Style x:Key="ResponsiveTextBoxStyle"
           TargetType="TextBox"
           BasedOn="{StaticResource {x:Type TextBox}}">
        <Setter Property="BorderBrush"
                Value="Blue" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TextBox}">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="*" />
                            <RowDefinition Height="Auto" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="Underline"
                                                         Storyboard.TargetProperty="(Border.Opacity)"
                                                         To="0"
                                                         Duration="0:00:00.25" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="MouseOver">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="Underline"
                                                         Storyboard.TargetProperty="(Border.Opacity)"
                                                         To="1"
                                                         Duration="0:00:00.25" />
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <ScrollViewer Margin="0"
                                      Grid.Row="0"
                                      Grid.ColumnSpan="4"
                                      x:Name="PART_ContentHost" />
                        <Border x:Name="Underline"
                                Grid.Row="1"
                                Opacity="0"
                                BorderThickness="1"
                                Height="2"
                                Grid.Column="1"
                                Grid.ColumnSpan="2"
                                BorderBrush="{TemplateBinding BorderBrush}" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>