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
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 am trying to change the background color when button gets click/focused but there is not any change occurring.
<Style x:Key="btnInputForm" TargetType="{x:Type Button}">
<Setter Property="FontSize" Value="22"/>
<Setter Property="Background" Value="#2f772b"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Width" Value="120"/>
<Setter Property="Height" Value="23"/>
<Setter Property="Button.RenderTransformOrigin" Value=".5,.5"/>
<Setter Property="TextElement.FontSize" Value="14" />
<Setter Property="TextElement.FontFamily" Value="Calibri" />
<Setter Property="Control.BorderBrush" Value="#085b09" />
<Setter Property="Control.BorderThickness" Value="1,1,1,1" />
<Setter Property="Margin" Value="3,10,3,3" />
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Bottom" />
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Background" Value="Yellow"/>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="White"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Green"/>
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Background" Value="Red"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="Yellow"/>
</Trigger>
</Style.Triggers>
</Style>
And the button:
<Button Content="Click Me" Height="30" Width="100"></Button>
I have a ToggleButton custom control which changes the text and size when toggled. I can change/set fonts and change the background/foreground properties and it works fine.
But as soon as I set the FontSize property of the ContentPresenter the text in the button gets misaligned! Specifically the vertical position seems to be off (Moves way down in the button)
I can't figure out what's causing this. If I don't set the fontsize everything works as intended. Here is my button.
<Style x:Key="PlusSelectedToggleButton" TargetType="{x:Type ToggleButton}" BasedOn="{x:Null}">
<Setter Property="Background" Value="#FF3498DB" />
<Setter Property="BorderBrush" Value="DarkGray" />
<Setter Property="Padding" Value="1"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border x:Name="Border" Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1" CornerRadius="4">
<ContentPresenter x:Name="ContentPresenter" RecognizesAccessKey="True"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="true">
<Setter Property="Background" Value="Black" TargetName="Border" />
<Setter Property="BorderBrush" Value="White" TargetName="Border" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="TextBlock.Foreground" Value="Black" TargetName="ContentPresenter" />
</Trigger>
<Trigger Property="IsEnabled" Value="true">
<Setter Property="Foreground" Value="White" />
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="Selected" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="TextBlock.Foreground" Value="DarkGray" TargetName="ContentPresenter" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Width" Value="75" TargetName="Border" />
<Setter Property="Height" Value="40" TargetName="Border" />
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Content" Value="+"/>
<Setter Property="TextBlock.FontSize" Value="50" TargetName="ContentPresenter"/>
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Background" Value="#FF3498DB" />
<Setter Property="Width" Value="40"/>
<Setter Property="Height" Value="40"/>
<Setter Property="TextBlock.Foreground" Value="White" TargetName="ContentPresenter" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Update: I got it to work but I still don't fully understand why I have to do this.
<Trigger Property="IsChecked" Value="False">
<Setter Property="Content" Value="+"/>
<Setter Property="TextBlock.Foreground" Value="White" TargetName="ContentPresenter" />
<Setter Property="TextBlock.FontSize" Value="27" TargetName="ContentPresenter"/>
<Setter Property="TextBlock.FontWeight" Value="Thin"></Setter>
<Setter Property="TextBlock.Height" Value="40" TargetName="ContentPresenter"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Background" Value="#FF3498DB" />
<Setter Property="Width" Value="35"/>
<Setter Property="Height" Value="35"/>
</Trigger>
I had to set the TextBlock.Height property to a much larger value (even larger then button height) to get the text to center vertically. Horizontally it stays at the same place. I'm not sure why it behaves like this.
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>