I am new to Styles and not sure on the best way to create a Button style to change the Foreground of IsMouseOver and IsPressed. I used a Border for a template because it has a CornerRadius and background and border properties. But Border does not have a Foreground property. Using Button as the template doesn't work well since the default look isn't being overridden.
What is a better way to style a Button template with Foreground behavior? Maybe using a label inside the border?
Here is the App.xaml:
<Application.Resources>
<Style TargetType="Button" x:Key="MyButton">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="MinHeight" Value="34"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="shortcutbutton"
BorderThickness="1"
BorderBrush="Black"
Background="Gray">
<ContentPresenter Margin="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
RecognizesAccessKey="True"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="shortcutbutton" Property="Background" Value="#FFDADADA" />
<Setter TargetName="shortcutbutton" Property="BorderBrush" Value="#EEEEEE" />
<!--<Setter TargetName="Border" Property="Foreground" Value="Black" />-->
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="shortcutbutton" Property="Background" Value="DarkGray" />
<Setter TargetName="shortcutbutton" Property="BorderBrush" Value="Black" />
<!--<Setter TargetName="Border" Property="Foreground" Value="Red" />-->
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
And the xaml:
<StackPanel HorizontalAlignment="Center" Height="100" VerticalAlignment="Center" Width="100">
<Button Content="Button" Height="41" Style="{DynamicResource MyButton}"/>
</StackPanel>
You need to move your Triggers from the ControlTemplate to the Style. Something like this:
<Style TargetType="Button">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="MinHeight" Value="34"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="shortcutbutton"
BorderThickness="1"
BorderBrush="Black"
Background="Gray">
<ContentPresenter Margin="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
RecognizesAccessKey="True"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Foreground" Value="#FFDADADA" />
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter Property="Foreground" Value="DarkGray" />
</Trigger>
</Style.Triggers>
</Style>
What you can do is set attached property of TextElement on the Border and like that every text element within your Border will be of that colour:
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="shortcutbutton" Property="Background" Value="#FFDADADA" />
<Setter TargetName="shortcutbutton" Property="BorderBrush" Value="#EEEEEE" />
<Setter TargetName="shortcutbutton" Property="TextElement.Foreground" Value="White"/>
</Trigger>
...
</ControlTemplate.Triggers>
Related
I made a simple style for the hyperlinks that target buttons:
<Style x:Key="Hyperlink" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Foreground" Value="{StaticResource ForegroundDarkBrush}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<TextBlock x:Name="innerText" Text="{TemplateBinding Content}" />
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="{StaticResource AppDarkBlueBrush}" />
<Setter TargetName="innerText" Property="TextDecorations" Value="Underline" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My problem is that, when applied to the button control that has set some properties like FontSize, FontWeight, FontFamily, they are simply ignored and do not work:
<Button
Command="{Binding OpenCommand}"
Content="Open"
FontSize="20"
Style="{StaticResource Hyperlink}" />
How can I make a TextBlock in my style template inherit such properties?
edit
Forgot my mention that properties like FontSize actually do work but only in the design mode.
You can indicate that you want your textblock to "inherit" some properties from the Button like this :
<Style x:Key="Hyperlink" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Foreground" Value="{StaticResource ForegroundDarkBrush}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<TextBlock
x:Name="innerText"
Text="{TemplateBinding Content}"
FontSize={TemplateBinding FontSize}
FontWeight={TemplateBinding FontWeight}
FontFamily={TemplateBinding FontFamily}
/>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="{StaticResource AppDarkBlueBrush}" />
<Setter TargetName="innerText" Property="TextDecorations" Value="Underline" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I want to change the color of my button permanently, if the user clicked a button. How do I achieve that in XAML?
The trigger I have right now won't work, because they are only temporary, not overriding default values.
Here my button template:
<Style TargetType="{x:Type Button}" x:Key="ButtonStyleNavigation">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="#FF365B74" />
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="FontFamily" Value="Arial" />
<!-- <Setter Property="BorderThickness" Value="2"/>-->
<!-- <Setter Property="BorderBrush" Value="Yellow"/>-->
<Setter Property="FontSize" Value="15" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border CornerRadius="10" Background="{TemplateBinding Background}">
<Grid>
<ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,5,0" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" Value="0.3"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Yellow" />
<Setter Property="Background" Value="#FF658EAA"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="Yellow" />
<Setter Property="Foreground" Value="#FF658EAA" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
SOLUTION:
So, I was able to get what I needed with the use of a ToggleButton. I've bound for each button one property to their IsChecked function.
In my ViewModel I change the checked-state accordingly to my desire. (mentioned in the comments)
Here is my new ToggleButton template:
<Style TargetType="{x:Type ToggleButton}" x:Key="ButtonStyleNavigation">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="#FF365B74" />
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="FontFamily" Value="Arial" />
<Setter Property="FontSize" Value="15" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border CornerRadius="10" Background="{TemplateBinding Background}" Height="19">
<Grid>
<ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,5,0" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Foreground" Value="Yellow" />
<Setter Property="Background" Value="#FF658EAA"/>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="#FF365B74" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Yellow" />
<Setter Property="Background" Value="#FF658EAA"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="Yellow" />
<Setter Property="Foreground" Value="#FF658EAA" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Sounds like you want a ToggleButton. They have a bool property called "IsChecked" that changes each time you click the button.
Taking the style you provided and changing it like so should achieve what you want.
<Style TargetType="{x:Type ToggleButton}" x:Key="ButtonStyleNavigation">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="#FF365B74" />
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="FontFamily" Value="Arial" />
<Setter Property="FontSize" Value="15" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border CornerRadius="10" Background="{TemplateBinding Background}">
<Grid>
<ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,5,0" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" Value="0.3"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="Yellow" />
<Setter Property="Foreground" Value="#FF658EAA" />
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="#FF658EAA" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I have removed the IsMouseOver trigger as it conflicts with the IsChecked triggers.
When you say you permanently i presume this is what you mean. If you wish for the button to remain the same colour after a user clicks on the button again, you will have to deal with click events and check for number of clicks on the button.
EDIT:
As per your comment, if you want to have only one button enabled at time, look into using radio buttons instead.
Here is a tutorial on getting multiple radio buttons set up.
Check out this answer on how to style them to look like normal buttons.
You can then use the triggers in a similar fashion to check for enum values in your view model.
Here is a pure xaml answer, using a ControlTemplate as requested, taking your original question and just changing the <ControlTemplate.Triggers> section:
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Button.Foreground).(SolidColorBrush.Color)" To="Yellow" Duration="0"/>
<ColorAnimation Storyboard.TargetProperty="(Button.Background).(SolidColorBrush.Color)" To="#FF658EAA" Duration="0"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
In your original question you had (perhaps unintentionally) triggered from the mouse over event, in which case change here the RoutedEvent accordingly.
NB. You may be able to find an alternative to ColourAnimation with a zero duration, but I thought I'd post this as it at least gives you something to work with.
I've looked through every answer here on StackOverflow but nothing fixed my problem.. I have following style written in App.xaml for my buttons. And this style is linked to my class in another assembly where data is being taken from.
This WORKS at runtime, but it's giving me a hard time inside designer.
There are no errors in the style itself, the error begings with ControlTemplate.
<Style x:Key="HeaderBTN" TargetType="{x:Type Button}">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Width" Value="36" />
<Setter Property="Padding" Value="5" />
<Setter Property="Background" Value="{Binding Path=(style:AppStyle.AccentMain)}" />
<Setter Property="Foreground" Value="{Binding Path=(style:AppStyle.AccentText)}" />
<Setter Property="FontSize" Value="20" />
<Setter Property="FontFamily" Value="Times New Roman" />
<Setter Property="Margin" Value="0" />
<Setter Property="DockPanel.Dock" Value="Right" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Name="border" BorderThickness="0" CornerRadius="0" Background="{TemplateBinding Background}">
<Grid>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Name="content"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{Binding Path=(style:AppStyle.AccentHover)}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="{Binding Path=(style:AppStyle.AccentButtonDown)}" />
<Setter Property="Foreground" Value="{Binding Path=(style:AppStyle.AccentTextDown)}" />
</Trigger>
<Trigger Property="IsDefaulted" Value="True">
<Setter Property="Background" Value="#3b3b3b" />
</Trigger>
<Trigger Property="IsFocused" Value="True">
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="#505050" />
<Setter Property="Foreground" Value="#A7A7A7" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Is there any alternative to this that would leave everything functional? It's important that these resources are dynamic because Users have to be able to change the theme.
Any help is appreciated.
P.S. I use Visual Studio 2013 Professional with Update 5
I'm trying to disable the MouseOver effect on buttons, or at least change the colour of it, in WPF.
I'm using the following style:
<Style x:Key="Borderless" TargetType="{x:Type Button}">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Button Background="{TemplateBinding Control.Background}"
Focusable="False">
<ContentPresenter
Margin="{TemplateBinding Control.Padding}"
HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"
ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
RecognizesAccessKey="True"
Content="{TemplateBinding ContentControl.Content}" />
</Button>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
in Window.Resources, which I thought would override all the default behaviours. But it doesn't.
Any suggestions?
Look what your control template boils down to:
<ControlTemplate TargetType="{x:Type Button}">
<Button>
<ContentPresenter/>
</Button>
</ControlTemplate>
You're saying, "I want to replace the look of my button with... a button." The usage of the ControlTemplate is to replace the visual tree of a control. So you are replacing the visual tree of the existing button with another button. If you want to start a button from scratch, try using the SimpleStyles button:
<Style TargetType="{x:Type Button}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="MinHeight" Value="23"/>
<Setter Property="MinWidth" Value="75"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Name="Border" CornerRadius="2" BorderThickness="1"
Background="#C0C0C0"
BorderBrush="#404040">
<ContentPresenter Margin="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
RecognizesAccessKey="True"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter TargetName="Border"
Property="BorderBrush" Value="#202020" />
</Trigger>
<Trigger Property="IsDefaulted" Value="true">
<Setter TargetName="Border"
Property="BorderBrush" Value="#202020" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="Border"
Property="Background" Value="#808080" />
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="Border"
Property="Background" Value="#E0E0E0" />
<Setter TargetName="Border"
Property="BorderBrush" Value="#606060" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="Border"
Property="Background" Value="#EEEEEE" />
<Setter TargetName="Border"
Property="BorderBrush" Value="#AAAAAA" />
<Setter Property="Foreground" Value="#888888"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Notice that this template creates a button the simplest possible way: a border that contains the button content. It does not use another button embedded inside the template.
from the following Trigger only the Foreground Setter is working. I do not understand why.
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red"/>
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="Foreground" Value="Red"/>
</Trigger>
Thanks for any help.
The reason this doesn't work is because the default Button template uses a ButtonChrome that draws the border and background and handles states like mouseover and disabled depending on the Windows theme (e.g. Windows XP style, Windows 7 style).
In order to allow your triggers to be applied, you will need to define a custom Button template that uses standard stylable WPF elements, like Border, instead of ButtonChrome. Here's a bare-bones working example:
<Button Content="button">
<Button.Style>
<Style TargetType="Button">
<Setter Property="BorderThickness" Value="3" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Property=Background}"
BorderBrush="{TemplateBinding Property=BorderBrush}"
BorderThickness="{TemplateBinding Property=BorderThickness}">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red" />
<Setter Property="BorderBrush" Value="Green" />
<Setter Property="Foreground" Value="Blue" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Button in WPF has a default control template. The correct way to override the Button's default behavior is by overriding default control template. This can be done with something similar to below:
<Button Width="100" Height="50" Content="Click Me!">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="bdr_main" CornerRadius="20" Margin="4" BorderThickness="1" BorderBrush="Black" Background="LightGray">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" Margin="8,6,8,6" ContentSource="Content" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bdr_main" Property="Background" Value="LightGreen"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="bdr_main" Property="Background" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
Found # http://harishasanblog.blogspot.com/2011/02/ismouseover-trigger-not-working-in-wpf.html
Hope it helps!
Try using the trigger on the controltemplate.
<ResourceDictionary>
<Style x:Key="TestButton" TargetType="Button">
<Setter Property="Height" Value="30" />
<Setter Property="Width" Value="30" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="Green" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Purple" />
</Trigger>
</ControlTemplate.Triggers>
<Grid>
<Rectangle Fill="{TemplateBinding Foreground}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>