Button background based on the content Textblock text - wpf

I am trying to set Button background color based on the TextBlock Text. TextBlock is part of the Button's Content and has been binded to viewmodel property.
<Button Style="{StaticResource ButtonStyle}">
<Button.Content>
<StackPanel>
<TextBlock Text="Title" />
<TextBlock Text="{Binding SomeValue, Mode=OneWay}" />
</StackPanel>
</Button.Content>
</Button>
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Name="bd">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
//HOW TO HERE...
<Trigger Property="Text" Value="SomeText 1">
<Setter TargetName="bd" Property="Background" Value="#b5e61d"/>
</Trigger>
<Trigger Property="Text" Value="SomeText 2">
<Setter TargetName="bd" Property="Background" Value="#99d9ea"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

I propose to include title TextBlock in Button's template and then create triggers based on Content value:
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Name="bd">
<StackPanel>
<TextBlock Text="Title" HorizontalAlignment="Center"/>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Content" Value="SomeText 1">
<Setter TargetName="bd" Property="Background" Value="#b5e61d"/>
</Trigger>
<Trigger Property="Content" Value="SomeText 2">
<Setter TargetName="bd" Property="Background" Value="#99d9ea"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Button Style="{StaticResource ButtonStyle}" Content="{Binding SomeValue}" />

Related

C# WPF Use multi image source ControlTemplate with Button.Tag

I have a problem on the using ControlTemplate in Button. I would like to create a button with image and text. When mouse over the button, the image change. I use the Button.Tag to pass the image source. But I need to pass two image sources. Is it possible to create a list of image source in Button.Tag and select in the ControlTemplate? Thanks you.
<Style x:Key="myBtnStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<StackPanel Orientation="Horizontal">
<Image x:Name="myImg" Source="{TemplateBinding Tag[0]}" HorizontalAlignment="Left"/>
<ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Left"/>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="myImg" Property="Source" Value="{TemplateBinding Tag[1]}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Button Content="Click" Style="{StaticResource myBtnStyle}">
<Button.Tag>
<ImageSource>/img/usb_white.png</ImageSource>
<ImageSource>/img/usb_gray.png</ImageSource>
</Button.Tag>
</Button>
You could set the Tag property to an ImageSource[] using the <x:Array> element:
<Button Content="Click" Style="{StaticResource myBtnStyle}">
<Button.Tag>
<x:Array Type="ImageSource">
<BitmapImage UriSource="Images/Buldingimage2.jpeg" />
<BitmapImage UriSource="Images/words.jpg" />
</x:Array>
</Button.Tag>
</Button>
You also need to replace the TemplateBindings in the template with bindings to TemplatedParent:
<Style x:Key="myBtnStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<StackPanel Orientation="Horizontal">
<Image x:Name="myImg" Source="{Binding Tag[0], RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Left"/>
<ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Left"/>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="myImg" Property="Source" Value="{Binding Tag[1], RelativeSource={RelativeSource TemplatedParent}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="btn_img" TargetType="Button">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Margin" Value="3"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="FontWeight" Value="Medium"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Background" Value="WhiteSmoke"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="2 0 0 0">
</ContentPresenter>
<ContentControl HorizontalAlignment="Left" Grid.Column="1" Content="{TemplateBinding Tag}" Margin="0 0 2 0"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource b_blue}"/>
<Setter Property="Foreground" Value="#fff"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="Gray"/>
<Setter Property="Foreground" Value="#fff"/>
</Trigger>
</Style.Triggers>
</Style>

Button IsPressed Trigger Not Working

I have a button with an undo image inside it.
I want the button to make the border appear when user clicks (ispressed) the button.
<Button Margin="0,7,12,0" HorizontalAlignment="Right" Height="20" Width="23">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="White"/>
<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="IsPressed" Value="True">
<Setter Property="BorderThickness" Value="1"/>
</Trigger>
<Trigger Property="IsPressed" Value="False">
<Setter Property="BorderThickness" Value="0"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
<Image Grid.Column="0" Grid.Row="0" Margin="0,0,0,0" Height="20" Width="20" Source="/Images/Undo.png">
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0.7"/>
</Trigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Button>
But its not working at all.
Any help will be appreciated!
I did the following changes to your style: 1) moved triggers within ControlTemplate; 2) assigned x:Name to Border so it can be referenced in the trigger; 3) defined BorderBrush.
<Button Margin="0" HorizontalAlignment="Center" Height="25" Width="75" VerticalAlignment="Center">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="b0" Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="BorderThickness" TargetName="b0" Value="1"/>
<Setter Property="BorderBrush" TargetName="b0" Value="Blue"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
<Image Grid.Column="0" Grid.Row="0" Margin="0,0,0,0" Height="20" Width="20" Source="/Images/Undo.jpg">
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0.7"/>
</Trigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Button>
It's not working because the button template sets the border thickness to 1 directly, ignoring the border thickness attribute of the button element itself. You're successfully changing a value that isn't used.
You will have to copy and modify the button template if you want to change the border thickness.

WPF button different images for one style

I dont understand why image is not displayed. I want different button images for one style.
I tried to set button image as imagebrush in button style, but then I will have the only one picture on all the buttons.
<Button
Height="64" Width="64" Margin="0,0,50,50"
Style="{DynamicResource MyButtonStyle}" VerticalAlignment="Bottom"
HorizontalAlignment="Right">
<Image Source="image1.png"/>
</Button>
<Button
Height="64" Width="64" Margin="0,0,125,50"
Style="{DynamicResource MyButtonStyle}" VerticalAlignment="Bottom"
HorizontalAlignment="Right">
<Image Source="image2.png"/>
</Button>
Button style
<Style x:Key="MyButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle x:Name="rectangle" Stroke="Black" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" TargetName="rectangle" Value="0.8"/>
<Setter Property="Stroke" TargetName="rectangle" Value="#FF478CFB"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="OpacityMask" TargetName="rectangle" Value="{x:Null}"/>
<Setter Property="Effect" TargetName="rectangle">
<Setter.Value>
<BlurEffect/>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Your style is missing ContentPresenter. Hence when you set the image as Content of a Button it has nowhere to actually put it when using your Style's ControlTemplate
So something like this:
Note - I've changed your Grid to a Border and thus got rid of a Rectangle embedded inside and added ContentPresenter as a child of Border
<Style x:Key="MyButtonStyle"
TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="rectangle">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="rectangle"
Property="Opacity"
Value="0.8" />
<Setter TargetName="rectangle"
Property="BorderBrush"
Value="#FF478CFB" />
</Trigger>
<Trigger Property="IsPressed"
Value="True">
<Setter TargetName="rectangle"
Property="OpacityMask"
Value="{x:Null}" />
<Setter TargetName="rectangle"
Property="Effect">
<Setter.Value>
<BlurEffect />
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Usage:
Same as you had -
<Button
Height="64" Width="64" Margin="0,0,125,50"
Style="{DynamicResource MyButtonStyle}" VerticalAlignment="Bottom"
HorizontalAlignment="Right">
<Image Source="image2.png"/>
</Button>

XAML Trigger WPF Tab selection changes more than the tab header

I have a trigger that when a tab is selected I color the tab blue and the text white, but the problem is that this trigger, for some reason, also changes the text color in the tabheader body to white as well in the group boxes. It seems that anything that has a header turns to white.
How do I make it so only the header in the tab itself
<TabItem Header="Query Editor" <-- This text only
will change to white when selected and no other text on the form?
Below is the code I am using.
Thanks.
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border Name="Border"
Background="WhiteSmoke"
BorderBrush="Black"
BorderThickness="1,1,1,1"
CornerRadius="6,6,0,0">
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,2,12,2"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="#00396a" />
<Setter Property="Foreground" Value="White" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="Border" Property="Background" Value="WhiteSmoke" />
<Setter Property="Foreground" Value="Black" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
may be TabItem.HeaderTemplate will work for you.
<TabControl>
<TabControl.Resources>
<DataTemplate x:Key="headerText">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock x:Name="content" Text="{Binding}" Grid.Column="1"/>
</Grid>
<DataTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.Setters>
<Setter TargetName="content" Property="Foreground" Value="white" />
</Trigger.Setters>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
<Style TargetType="TabItem">
<Style.Setters>
<Setter Property="HeaderTemplate" Value="{StaticResource headerText}" />
</Style.Setters>
</Style>
</TabControl.Resources>
<TabItem Header="fsdf" >
<TextBlock Text="lkajsldkjaskl" />
</TabItem>
<TabItem Header="ghj">
<TextBlock Text="ghj" />
</TabItem>
<TabItem Header="fs556df">
<TextBlock Text="jjj" />
</TabItem>
</TabControl>
</TabItem>
</TabControl>
you could have 2headerstyle, one normal one selected. in your tabitem style triggers you can set the headertemplate to the right "IsSelected" one.
The solution!
Thank you all for your help.
What I changed was I removed the ContentPresenter and replaced it with the textblock that only affected the tab header itself.
<TabControl.Resources>
<Style TargetType="{x:Type TabControl}">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush>
<GradientStop Offset="0" Color="WhiteSmoke"/>
<GradientStop Offset="4" Color="GhostWhite"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="Black" />
</Style>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border Name="Border"
Background="WhiteSmoke"
BorderBrush="Black"
BorderThickness="1,1,1,1"
CornerRadius="6,6,0,0">
<TextBlock
x:Name="TabItemContent"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Text="{TemplateBinding Header}"
Margin="12,2,12,2" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="#00396a" />
<Setter Property="Foreground" TargetName="TabItemContent" Value="White"/>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="Border" Property="Background" Value="WhiteSmoke" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>

Link button in wpf

How can I make Button to look like LinkButton, and I don't want to use
Hyperlink...!!
Any suggestions
If you don't want any of the normal Button style and just want something that looks like a hyperlink you could start with this
<Button Margin="5" Content="Test" Cursor="Hand">
<Button.Template>
<ControlTemplate TargetType="Button">
<TextBlock TextDecorations="Underline">
<ContentPresenter />
</TextBlock>
</ControlTemplate>
</Button.Template>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Foreground" Value="Blue" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Here's the same as a style:
<Style
x:Key="LinkButton"
TargetType="Button">
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="Button">
<TextBlock
TextDecorations="Underline">
<ContentPresenter /></TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter
Property="Foreground"
Value="Blue" />
<Style.Triggers>
<Trigger
Property="IsMouseOver"
Value="true">
<Setter
Property="Foreground"
Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
and you can use it like this:
<Button Style="{StaticResource LinkButton}" Content="Clicky" />
<Style x:Key="LinkButton"
TargetType="Button"
BasedOn="{StaticResource ResourceKey={x:Type Button}}"
>
<Setter Property="Width" Value="Auto"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ContentPresenter Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
VerticalAlignment="Center"
>
<ContentPresenter.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="TextDecorations" Value="Underline" />
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="Blue" />
<Setter Property="Cursor" Value="Hand" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
MichaC's and Anderson's version placed the underline slightly wrong, here is an updated version that will just add an underline to any TextBlock that are inside the ContentPresenter.
Here's MichaC's suggestion implemented as a Style that you can reuse on any button:
<Style x:Key="LinkButton" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<TextBlock TextDecorations="Underline">
<ContentPresenter />
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="Blue" />
<Setter Property="Cursor" Value="Hand" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
The easiest way (I do this in my application):
<TextBlock Name="..."
Text="..."
Cursor="Hand"
Foreground="Blue"
TextDecorations="Underline"
MouseLeftButtonUp=..."
/>
you have full control on TextDecoration, e.g. change pen style or offset.
take a look at this link to find out more: http://msdn.microsoft.com/en-us/library/system.windows.textdecorations.underline.aspx
Another solution using Hyperlink is to put in inside TextBlock.
<TextBlock>
<Hyperlink Click="...">
<TextBlock Text="Link text" />
</Hyperlink>
</TextBlock>
Why do you not want to use Hyperlink?
<Button>
<Hyperlink>
</Button>
Combination of all proposed solutions:
Completed style, as in the accepted version, but without hardcoded values.
<Style
x:Key="HyperlinkButton"
TargetType="{x:Type Button}"
BasedOn="{StaticResource {x:Type Button}}"
>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<TextBlock>
<Hyperlink
Command="{TemplateBinding Command}"
CommandTarget="{TemplateBinding CommandTarget}"
CommandParameter="{TemplateBinding CommandParameter}"
>
<ContentPresenter />
</Hyperlink>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Resources