I wanted to achieve the below Textbox design.
I thought of using UserControl to make it reusable.
<UserControl
x:Class="Test.UserControls.TextBoxControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="ACS.UserControls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<UserControl.Resources>
<Style x:Key="UserControlRegularTextBox" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="{DynamicResource BrushTextBoxBackgroundNormal}" />
<Setter Property="Foreground" Value="{DynamicResource BrushColorFont}" />
<Setter Property="BorderBrush" Value="{StaticResource BrushTextBoxBorder}" />
<Setter Property="KeyboardNavigation.TabNavigation" Value="None" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="AllowDrop" Value="true" />
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst" />
<Setter Property="Stylus.IsFlicksEnabled" Value="False" />
<Setter Property="FontFamily" Value="{DynamicResource OpenSansExtraBold}" />
<Setter Property="FontSize" Value="7" />
<Setter Property="SelectionBrush" Value="{DynamicResource BrushTextSelection}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border
x:Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1,1,0,1"
CornerRadius="2 0 0 2"
SnapsToDevicePixels="True">
<ScrollViewer
x:Name="PART_ContentHost"
Focusable="false"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="border" Property="Opacity" Value="0.56" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource BrushTextBoxBorderMouseOver}" />
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource BrushTextBoxBorderFocusd}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsInactiveSelectionHighlightEnabled" Value="true" />
<Condition Property="IsSelectionActive" Value="false" />
</MultiTrigger.Conditions>
<Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}" />
</MultiTrigger>
</Style.Triggers>
</Style>
<Style x:Key="FocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle
Margin="0"
SnapsToDevicePixels="true"
Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"
StrokeDashArray="1 2"
StrokeThickness="0" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="TextBoxControlClearButtonStyle" TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}" />
<Setter Property="Background" Value="{DynamicResource BrushTextBoxBackgroundNormal}" />
<Setter Property="BorderBrush" Value="{DynamicResource BrushTextBoxBorder}" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Padding" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border
x:Name="border"
Margin="0"
Padding="0"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="0,1,1,1"
CornerRadius="0 2 2 0"
SnapsToDevicePixels="true">
<StackPanel
Margin="0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Horizontal">
<Path
x:Name="path"
Width="5"
Height="5"
Data="M 18,11 27,20 M 18,20 27,11"
Stretch="Uniform"
Stroke="{DynamicResource InputColorIcon}" />
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsDefaulted" Value="true">
<Setter TargetName="border" Property="Background" Value="{DynamicResource BrushTextBoxBackgroundNormal}" />
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource BrushTextBoxBorder}" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="border" Property="Background" Value="{DynamicResource BrushColorPrimary}" />
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource BrushColorPrimary}" />
<Setter TargetName="path" Property="Stroke" Value="{DynamicResource BrushColorWhite}" />
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="border" Property="Background" Value="{DynamicResource Button.Pressed.Background}" />
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource Button.Pressed.Background}" />
<Setter TargetName="path" Property="Stroke" Value="{DynamicResource BrushColorWhite}" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="border" Property="Background" Value="{DynamicResource Button.Disabled.Background}" />
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource Button.Disabled.Border}" />
<Setter TargetName="path" Property="Stroke" Value="{DynamicResource BrushColorWhite}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<StackPanel Orientation="Horizontal">
<TextBox
x:Name="TextBoxInput"
Width="100"
Height="auto"
Margin="0"
Padding="4,4,2,4"
GotFocus="OnFocused"
LostFocus="OnLostFocus"
MouseEnter="OnHover"
MouseLeave="OnHoverOut"
Style="{DynamicResource UserControlRegularTextBox}"
Text="Hello World! This is a sample text input."
TextChanged="OnTextChanged" />
<Button
x:Name="BtnClearInput"
Width="20"
Height="auto"
Margin="0,0,0,0"
HorizontalAlignment="Right"
Click="OnClearInput"
Style="{DynamicResource TextBoxControlClearButtonStyle}" />
</StackPanel>
</UserControl>
Unfortunately, I have two problems. The first one is that the clear button is always visible. It should be only visible when the textbox is focused. The second one is that the border of the clear button is not the same as the textbox when focusing/hovering.
I'm still thinking about how to solve the first problem, but the second one maybe is to copy the border of the textbox into the clear button when it is being hovered or focused, for example;
public partial class TextBoxControl : UserControl
{
public TextBoxControl()
{
InitializeComponent();
this.DataContext = this;
}
private void OnFocused(object sender, RoutedEventArgs e)
{
BtnClearInput.BorderBrush = ((TextBox)sender).BorderBrush;
}
private void OnLostFocus(object sender, RoutedEventArgs e)
{
BtnClearInput.BorderBrush = ((TextBox)sender).BorderBrush;
}
private void OnHover(object sender, MouseEventArgs e)
{
BtnClearInput.BorderBrush = ((TextBox)sender).BorderBrush;
}
private void OnHoverOut(object sender, MouseEventArgs e)
{
BtnClearInput.BorderBrush = ((TextBox)sender).BorderBrush;
}
private void OnClearInput(object sender, RoutedEventArgs e)
{
TextBoxInput.Clear();
}
}
}
But this only gets the default border color of the textbox.
This is what I have right now;
CodePudding user response:
You could try solving the border by finding the resource key.
(Brush)FindResource("your_resource_key");
replace your textbox event with the following and see if that solve the issue.
private void OnFocused(object sender, RoutedEventArgs e){
BtnClearInput.BorderBrush = (Brush)FindResource("BrushTextBoxBorderFocusd");
}
private void OnLostFocus(object sender, RoutedEventArgs e){
BtnClearInput.BorderBrush = (Brush)FindResource("BrushTextBoxBorder");
}
private void OnHover(object sender, MouseEventArgs e){
BtnClearInput.BorderBrush = (((TextBox)sender).IsFocused == true) ? (Brush)FindResource("BrushTextBoxBorderFocusd") : (Brush)FindResource("BrushTextBoxBorderMouseOver");
}
private void OnHoverOut(object sender, MouseEventArgs e){
BtnClearInput.BorderBrush = (((TextBox)sender).IsFocused == true) ? (Brush)FindResource("BrushTextBoxBorderFocusd") : (Brush)FindResource("BrushTextBoxBorder");
}
then regarding the visibility of the clear button, hide it by default then set the visibility to visible on textbox focus. For example, the clear button should be <Button x:Name="BtnClearInput" Visibility="Hidden" ... />
Then on your textbox focus
private void OnFocused(object sender, RoutedEventArgs e){
BtnClearInput.Visibility = Visibility.Visible; //don't forget to hide this when you lost focus to textbox.
BtnClearInput.BorderBrush = (Brush)FindResource("BrushTextBoxBorderFocusd");
}
You can move the Button in your Textbox template. Just put your <ScrollViewer x:Name="PART_ContentHost">
into grid, then add the button.
<UserControl
x:Class="Test.UserControls.TextBoxControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="ACS.UserControls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<UserControl.Resources>
<Style x:Key="UserControlRegularTextBox" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="{DynamicResource BrushTextBoxBackgroundNormal}" />
<Setter Property="Foreground" Value="{DynamicResource BrushColorFont}" />
<Setter Property="BorderBrush" Value="{StaticResource BrushTextBoxBorder}" />
<Setter Property="KeyboardNavigation.TabNavigation" Value="None" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="AllowDrop" Value="true" />
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst" />
<Setter Property="Stylus.IsFlicksEnabled" Value="False" />
<Setter Property="FontFamily" Value="{DynamicResource OpenSansExtraBold}" />
<Setter Property="FontSize" Value="7" />
<Setter Property="SelectionBrush" Value="{DynamicResource BrushTextSelection}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border
x:Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1,1,1,1"
CornerRadius="2 2 2 2"
SnapsToDevicePixels="True">
<!--Grid added and moved your button in here. -->
<Grid x:Name="LayoutGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ScrollViewer
x:Name="PART_ContentHost"
Grid.Column="0"
Focusable="false"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden" />
<Button
x:Name="PART_Cleariconborder"
Grid.Column="0"
Width="20"
Height="auto"
Margin="1"
HorizontalAlignment="Right"
Click="OnClearInput"
Opacity="0"
Style="{DynamicResource TextBoxControlClearButtonStyle}" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="border" Property="Opacity" Value="0.56" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource BrushTextBoxBorderMouseOver}" />
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource BrushTextBoxBorderFocusd}" />
<Setter TargetName="PART_Cleariconborder" Property="Opacity" Value="1" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsInactiveSelectionHighlightEnabled" Value="true" />
<Condition Property="IsSelectionActive" Value="false" />
</MultiTrigger.Conditions>
<Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}" />
</MultiTrigger>
</Style.Triggers>
</Style>
<Style x:Key="TextBoxControlClearButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background" Value="{DynamicResource BrushTextBoxBackgroundNormal}" />
<Setter Property="BorderBrush" Value="{DynamicResource BrushTextBoxBorder}" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Padding" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border
x:Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
CornerRadius="0 2 2 0"
SnapsToDevicePixels="true">
<Path
x:Name="path"
Width="5"
Height="5"
Data="M 18,11 27,20 M 18,20 27,11"
Stretch="Uniform"
Stroke="{DynamicResource InputColorIcon}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsDefaulted" Value="true">
<Setter TargetName="border" Property="Background" Value="{DynamicResource BrushTextBoxBackgroundNormal}" />
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource BrushTextBoxBorder}" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="border" Property="Background" Value="{DynamicResource BrushColorSecondary}" />
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource BrushColorSecondary}" />
<Setter TargetName="border" Property="Margin" Value="-2,-2,-2,-1" />
<Setter TargetName="path" Property="Stroke" Value="{DynamicResource BrushColorWhite}" />
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="border" Property="Background" Value="{DynamicResource BrushColorPrimary}" />
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource BrushColorPrimary}" />
<Setter TargetName="border" Property="Margin" Value="-2,-2,-2,-1" />
<Setter TargetName="path" Property="Stroke" Value="{DynamicResource BrushColorWhite}" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="border" Property="Background" Value="{DynamicResource Button.Disabled.Background}" />
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource Button.Disabled.Border}" />
<Setter TargetName="path" Property="Stroke" Value="{DynamicResource BrushColorWhite}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<TextBox
x:Name="TextBoxInput"
Width="auto"
Height="auto"
Margin="0"
Padding="4,4,22,4"
Style="{DynamicResource UserControlRegularTextBox}"
Text=""
TextChanged="OnTextChanged" />
</UserControl>
CodePudding user response:
Polar's revised answer is almost same as what I had in mind. The following is alternative one which is a little bit simplyfied. Just for your reference.
<UserControl
x:Class="Test.UserControls.TextBoxControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="ACS.UserControls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<UserControl.Resources>
<Style x:Key="FocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle
Margin="0"
SnapsToDevicePixels="true"
Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"
StrokeDashArray="1 2"
StrokeThickness="0" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="TextBoxControlClearButtonStyle" TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}" />
<Setter Property="Background" Value="{DynamicResource BrushTextBoxBackgroundNormal}" />
<Setter Property="Foreground" Value="{DynamicResource InputColorIcon}"/>
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="border"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="true"
UseLayoutRounding="True">
<Path x:Name="path"
Width="5"
Height="5"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Data="M 18,11 27,20 M 18,20 27,11"
Stretch="Uniform"
Stroke="{TemplateBinding Foreground}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="UserControlRegularTextBox" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="{DynamicResource BrushTextBoxBackgroundNormal}" />
<Setter Property="Foreground" Value="{DynamicResource BrushColorFont}" />
<Setter Property="BorderBrush" Value="{StaticResource BrushTextBoxBorder}" />
<Setter Property="KeyboardNavigation.TabNavigation" Value="None" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="AllowDrop" Value="true" />
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst" />
<Setter Property="Stylus.IsFlicksEnabled" Value="False" />
<Setter Property="FontFamily" Value="{DynamicResource OpenSansExtraBold}" />
<Setter Property="FontSize" Value="7" />
<Setter Property="SelectionBrush" Value="{DynamicResource BrushTextSelection}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1"
CornerRadius="2"
ClipToBounds="True"
SnapsToDevicePixels="True"
UseLayoutRounding="True">
<Grid>
<ScrollViewer x:Name="PART_ContentHost"
Focusable="false"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden" />
<Button x:Name="button"
Width="20"
HorizontalAlignment="Right"
Style="{StaticResource TextBoxControlClearButtonStyle}"
Visibility="Collapsed"
Click="OnClearInput"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="border" Property="Opacity" Value="0.56" />
<Setter TargetName="button" Property="Background" Value="{DynamicResource Button.Disabled.Background}" />
<Setter TargetName="button" Property="Foreground" Value="{DynamicResource BrushColorWhite}" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource BrushTextBoxBorderMouseOver}" />
<Setter TargetName="button" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource BrushTextBoxBorderFocusd}" />
<Setter TargetName="button" Property="Visibility" Value="Visible" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsKeyboardFocused" Value="false"/>
<Condition SourceName="button" Property="IsMouseOver" Value="true"/>
</MultiTrigger.Conditions>
<Setter TargetName="button" Property="Background" Value="{DynamicResource BrushTextBoxBorderMouseOver}"/>
<Setter TargetName="button" Property="Foreground" Value="{DynamicResource BrushColorWhite}"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsKeyboardFocused" Value="true"/>
<Condition SourceName="button" Property="IsMouseOver" Value="true"/>
</MultiTrigger.Conditions>
<Setter TargetName="button" Property="Background" Value="{DynamicResource BrushTextBoxBorderFocusd}"/>
<Setter TargetName="button" Property="Foreground" Value="{DynamicResource BrushColorWhite}"/>
</MultiTrigger>
<Trigger SourceName="button" Property="IsPressed" Value="true">
<Setter TargetName="button" Property="Background" Value="{DynamicResource Button.Pressed.Background}" />
<Setter TargetName="button" Property="Foreground" Value="{DynamicResource BrushColorWhite}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsInactiveSelectionHighlightEnabled" Value="true" />
<Condition Property="IsSelectionActive" Value="false" />
</MultiTrigger.Conditions>
<Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}" />
</MultiTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<TextBox x:Name="TextBoxInput"
Style="{StaticResource UserControlRegularTextBox}"
Width="120"
Height="auto"
Margin="0"
Padding="4,4,2,4"
Text="Hello World! This is a sample text input."
TextChanged="OnTextChanged"/>
</UserControl>