Set border image for Textbox on focus - wpf

I want to set an image as border when a text box has got focus. I know how to set the border color when the text box gets focus as follows
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="BorderThickness" Value="2.20" />
<Setter Property="BorderBrush" Value="#f8cb1c" />
</Trigger>
</Style.Triggers>
</Style>
but how can I set an image for border or around a textbox.

<Style x:Key="TextBoxStyle1" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate 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">
<Grid>
<Image x:Name="imgctrl" Stretch="Fill"/>
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Grid>
</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>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Source" TargetName="imgctrl" Value="5.jpg"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

I would hide the default TextBox border, and place it on top of an Image containing the border image you want, and show the Image when the TextBox is selected
<Style x:Key="BorderImageStyle" TargetType="{x:Type Image}">
<Setter Property="IsVisible" Value="False" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=SomeTextBox, Path=IsKeyboardFocusWithin}" Value="True">
<Setter Property="IsVisible" Value="True" />
</DataTrigger>
</Style>
<Grid>
<Image x:Name="BorderImage" ... />
<TextBox x:Name="SomeTextBox" BorderThickness="0" Margin="20" ... />
</Grid>

Related

IntegerUpDown Style Up/down buttons

I am trying to style a integerupdown(Xceed framework) control and my wpf knowledge in lacking. So far I have gotten it styled for everything but the OnMouseOver which still looks like a "normal" button mouseover.
How can I set the style on mouseover? Remove the blue automatic background.
<UserControl.Resources>
<Style x:Key="{x:Static theme:ResourceKeys.SpinnerButtonStyleKey}" TargetType="RepeatButton">
<Setter Property="Foreground" Value="#fff" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Background" Value="#555555"></Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red"></Setter>
<Setter Property="Background" Value="Black"></Setter>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type xctk:IntegerUpDown}">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static theme:ResourceKeys.GlyphNormalForegroundKey}" Color="#e9e9ee"/>
</Style.Resources>
</Style>
</UserControl.Resources>
You should define a custom RepeatButton style for the themes:ResourceKeys.SpinnerButtonStyleKey resource:
<xctk:IntegerUpDown
xmlns:themes="clr-namespace:Xceed.Wpf.Toolkit.Themes;assembly=Xceed.Wpf.Toolkit"
xmlns:chrome="clr-namespace:Xceed.Wpf.Toolkit.Chromes;assembly=Xceed.Wpf.Toolkit">
<xctk:IntegerUpDown.Resources>
<Style x:Key="{x:Static themes:ResourceKeys.SpinnerButtonStyleKey}"
TargetType="RepeatButton">
<Setter Property="Background" Value="{DynamicResource {x:Static themes:ResourceKeys.ButtonNormalBackgroundKey}}" />
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static themes:ResourceKeys.ButtonNormalOuterBorderKey}}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Padding" Value="2,2" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RepeatButton">
<Grid>
<chrome:ButtonChrome x:Name="Chrome"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
CornerRadius="{DynamicResource {x:Static themes:ResourceKeys.SpinButtonCornerRadiusKey}}"
RenderEnabled="{TemplateBinding IsEnabled}"
RenderMouseOver="False"
RenderNormal="True"
RenderPressed="{TemplateBinding IsPressed}"
SnapsToDevicePixels="true" />
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="{TemplateBinding Padding}" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</xctk:IntegerUpDown.Resources>
</xctk:IntegerUpDown>

How to change border color using triggers in WPF?

I need to change border color of one text box when mouse hover him, but with solution i write it does not work. Is there mistake in my code?
Background color changes, but border no.
Code below is my idea.
<Style x:Key="BorderColor" TargetType="TextBox">
<Setter Property="FontStyle" Value="Normal"/>
<Style.Triggers>
<Trigger Property="TextBox.IsMouseOver" Value="true">
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="Background" Value="LightBlue"/>
</Trigger>
</Style.Triggers>
A quick and easy way to do this is to simply set the TextBox border thickness to 0 and encapsulate it in a parent border:
<Border BorderThickness="1" Width="500" Height="20" >
<Border.Style>
<Style TargetType="{x:Type Border}">
<Setter Property="BorderBrush" Value="Black" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBox x:Name="theTextBox" BorderThickness="0" />
</Border>
The "proper" way to do this is to template the entire control:
<Style TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" TargetName="border" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Color of button border is controlled by template triggers of a button via button (Templated Parent) properties. Since priority of such triggers is almost the top most, you need to redefine control template of a button.
https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/dependency-property-value-precedence

TextBox focus border AND placeholder text

I want to create a textbox with placeholder text, that doesn't turn blue on mouse over/focus.
Through experimentation and scouring the internet I've found that the following code is the simplest solutions to the individual problems.
Placeholder Text
<Style x:Key="PlaceHolderTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<TextBox Text="{Binding Path=Text,
RelativeSource={RelativeSource TemplatedParent},
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
x:Name="textSource"
Background="Transparent"
Panel.ZIndex="2" />
<TextBox Text="{TemplateBinding Tag}" Background="{TemplateBinding Background}" Panel.ZIndex="1">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="Transparent"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Text, Source={x:Reference textSource}}" Value="">
<Setter Property="Foreground" Value="Gray"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Focus Border replacement
<Style x:Key="CustomBorderTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="#000000"/>
</Trigger>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="Yellow"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
However, you can't just combine them. Putting both the grid and border in one ControlTemplate doesn't work, so how would you create a style that replaces the border and also displays placeholder text (preferably without code-behind)?
combine them by adding a panel (Grid) which can have more than one child.
I took "CustomBorderTextBox" as base and added placehold TextBlock which becomes visible when text is empty. Placeholder text is stored TextBox.Tag
<Style x:Key="CustomTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid>
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
<TextBlock Text="{TemplateBinding Tag}" IsHitTestVisible="False">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Hidden"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Text, RelativeSource={RelativeSource AncestorType=TextBox}}"
Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="#000000"/>
</Trigger>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="Yellow"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

wpf button background hover color

I'm trying to change the background colour of a button's style in xaml on hover
This is my current approach, but it doesn't work. The default hover colour is being used
<Style x:Key="AtStyle" TargetType="Button">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="{StaticResource AtBlue}" />
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="White" />
<Setter Property="Padding" Value="12,6" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="FontSize" Value="18.667" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Red" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
I've seen other solutions that say that you need to override the Control template to achieve this, but those solutions also require you define the border and the content as well which seems unnecessary. What is the minimal approach to defining a hover state in Xaml?
I have created simple style based button based on your requirement,
XAML
<Style TargetType="Button">
<Setter Property="Background"
Value="Blue" />
<Setter Property="HorizontalAlignment"
Value="Center" />
<Setter Property="VerticalAlignment"
Value="Center" />
<Setter Property="Foreground"
Value="White" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="bg"
Background="{TemplateBinding Background}"
BorderThickness="2"
BorderBrush="White">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Background"
Value="Red"
TargetName="bg" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Let's look at the template of the default button style for Aero theme:
<ControlTemplate TargetType="{x:Type ButtonBase}">
<theme:ButtonChrome Name="Chrome"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
RenderDefaulted="{TemplateBinding Button.IsDefaulted}"
RenderMouseOver="{TemplateBinding IsMouseOver}"
RenderPressed="{TemplateBinding IsPressed}"
SnapsToDevicePixels="True">
<ContentPresenter
Margin="{TemplateBinding Padding}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
RecognizesAccessKey="True"/>
</theme:ButtonChrome>
<ControlTemplate.Triggers>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter TargetName="Chrome" Property="RenderDefaulted" Value="True"/>
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="True">
<Setter TargetName="Chrome" Property="RenderPressed" Value="True"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="#ADADAD"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
As you can see, the mouse-over and pressed colors are defined as bindings on the ButtonChrome's properties RenderMouseOver and RenderPressed. The way ButtonChrome is designed, they take priority over any values from the Background property. Therefore, unfortunately, the only way to override background color of a clicked or highlighted button is to override its template.

WPF: How to implement Blend's Dark theme for context menu

I have added this xaml in my App.xaml:
<Style TargetType="{x:Type ContextMenu}">
<Setter Property="Background" Value="{StaticResource ShadeBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource ShadeBrush}" />
<Setter Property="Foreground" Value="White" />
</Style>
This gets me most of the way towards a dark theme....
How do I fix this problem with the menu items:
I suspect I need to modify the style or template for the menuitem.
Thanks.
UPDATE: Using Snoop (mentioned by Andy, thanks), I find this when selecting the white rect:
For whoever comes here next, I solved this problem by setting the template like so:
<Style TargetType="{x:Type ContextMenu}">
<Setter Property="Background" Value="{StaticResource ShadeBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource ShadeBrush}" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContextMenu}">
<Border Uid="Border_93">
<Border.Style>
<Style TargetType="{x:Type Border}">
<Setter Property="Tag"
Value="{DynamicResource
{x:Static SystemParameters.DropShadowKey}}"/>
<Style.Triggers>
<DataTrigger
Binding="{Binding Tag,
RelativeSource={RelativeSource Self}}"
Value="True">
<Setter Property="Background"
Value="Transparent"/>
<Setter Property="Padding"
Value="0,0,5,5"/>
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect
BlurRadius="4"
Opacity="0.8"
ShadowDepth="1"/>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Uid="Border_50">
<ScrollViewer CanContentScroll="True"
Style="{DynamicResource {ComponentResourceKey ResourceId=MenuScrollViewer,
TypeInTargetAssembly={x:Type FrameworkElement}}}"
Uid="ScrollViewer_9">
<ItemsPresenter
KeyboardNavigation.DirectionalNavigation="Cycle"
Margin="{TemplateBinding Padding}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
Uid="ItemsPresenter_5"/>
</ScrollViewer>
</Border>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Resources