WPF styling tab items as arrow-like - wpf

I want to style my TabControl to have items similar to this:
I tried to the combination of Border (with right thickness of 0) and triangle shaped polygon with pushing the polygon out of bound a bit to overlap, but its not really working as the out of bounds part of polygon gets hidden. Here is my attempt and now I am stuck and don't really know what else to try:
<!-- Styles -->
<Style TargetType="{x:Type TabItem}">
<Setter Property="Padding" Value="15 0 15 0" />
<Setter Property="Background" Value="#f5f5f5" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid ClipToBounds="False">
<Border x:Name="PART_Border"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderThickness="1 1 0 1"
BorderBrush="LightGray">
<ContentPresenter ContentSource="Header" VerticalAlignment="Center" />
</Border>
<Polygon Points="0,0 20,25, 0,50"
Stroke="#e8e8e8"
Fill="#ffffff"
HorizontalAlignment="Right"
Margin="0 0 -10 0"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="PART_Border" Property="Background" Value="#ffffff" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Content -->
<TabControl>
<TabItem Header="First" />
<TabItem Header="Second" />
<TabItem Header="Third" />
</TabControl>

This will do the job for you:
<Style TargetType="{x:Type TabItem}">
<Setter Property="Background" Value="#f5f5f5" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Path x:Name="Back" Data="M0,0 L 80,0 L100,20 L80,40 L0,40 L 20,20 " Stretch="None" VerticalAlignment="Stretch"
Stroke="#e8e8e8" StrokeThickness="2"
Fill="{TemplateBinding Background}"
HorizontalAlignment="Stretch" Margin="-30,0,0,0"/>
<ContentPresenter ContentSource="Header" VerticalAlignment="Center" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Back" Property="Fill" Value="#ffffff" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Instead of the border and polygon I used a Path to draw the shape for you.
You can use - (minus) values in margins to overlap items.
Result:

Related

WPF: Get rid of shadow in tab headers

I have the following code:
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type TabItem}" x:Key="TabItemStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Border x:Name="Chrome"
BorderBrush="Blue"
Background="Transparent">
<ContentPresenter ContentSource="Header"
Margin="0,0,0,3"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Selector.IsSelected" Value="True">
<Setter TargetName="Chrome" Property="BorderThickness" Value="0,0,0,3"/>
</Trigger>
<Trigger Property="Selector.IsSelected" Value="False">
<Setter TargetName="Chrome" Property="BorderThickness" Value="0,0,0,0"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<Grid.Effect>
<DropShadowEffect Color="Black"
BlurRadius="10"
Opacity="0.25"
ShadowDepth="4"
Direction="270" />
</Grid.Effect>
<TabControl Background="Transparent">
<TabItem Style="{DynamicResource TabItemStyle}" Header="Tab 1" />
<TabItem Style="{DynamicResource TabItemStyle}" Header="Tab 2" />
</TabControl>
</Grid>
The grid has a DropshadowEffect which I need.
The TabControl's background must be Transparent.
I have a style for the TabItems which I need.
The style for the TabItems cause the tab headers to have a shadow. I don't want that shadow.
Is there a way to get rid of the shadow on the TabItem headers?
But keep the shadow on the Grid.
Please help!
Best regards
/Steffe
You could try to apply the effect to a sibling Grid:
<Grid>
<Grid Background="White">
<Grid.Effect>
<DropShadowEffect Color="Black"
BlurRadius="10"
Opacity="0.25"
ShadowDepth="4"
Direction="270" />
</Grid.Effect>
</Grid>
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type TabItem}" x:Key="TabItemStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Border x:Name="Chrome"
BorderBrush="Blue"
Background="Transparent">
<ContentPresenter ContentSource="Header"
Margin="0,0,0,3"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Selector.IsSelected" Value="True">
<Setter TargetName="Chrome" Property="BorderThickness" Value="0,0,0,3"/>
</Trigger>
<Trigger Property="Selector.IsSelected" Value="False">
<Setter TargetName="Chrome" Property="BorderThickness" Value="0,0,0,0"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<TabControl Background="Transparent">
<TabItem Style="{DynamicResource TabItemStyle}" Header="Tab 1" />
<TabItem Style="{DynamicResource TabItemStyle}" Header="Tab 2" />
</TabControl>
</Grid>
</Grid>
Then it won't affect the TabControl.

Change image on button on MouseOver XAML (WPF)

I am working on application and one requirement is to change the image of the button on mouse hover.
Below is my code for button,
<Grid Margin="0 20 0 0" Name="ButtonsGrid" Width="300">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button x:Name="AnswerButton" Style="{StaticResource hover2}" Grid.Column="0" VerticalAlignment="Center" HorizontalContentAlignment="Center" Width="60" Height="60" Background="Transparent" IsEnabled="False" Click="AnswerButton_OnClick" BorderBrush="Transparent" BorderThickness="0" >
<Image Source="/Training.Project.Demo;component/Images/Answer.PNG" Stretch="UniformToFill"/>
</Button>
And below is the style i am applying,
<Style x:Key="hover2" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center">
<ContentPresenter.Content>
<Border Name="border"
BorderThickness="0"
BorderBrush="Transparent"
Background="{TemplateBinding Background}">
<Image x:Name="ButtonImage1" Source="/Training.Project.Demo;component/Images/Answer.PNG" Height="17" Width="17" />
</Border>
</ContentPresenter.Content>
</ContentPresenter>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="Black" />
<Setter TargetName="ButtonImage1" Property="Source" Value="/Training.Project.Demo;component/Images/answer-hover.PNG" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I am not sure what wrong am i doing but the above code is not working.
Any help would be appreciated
Remove IsEnabled="True" and define the Border element in the ControlTemplate itself and not in a ContentPresenter:
<Style x:Key="hover2" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="border"
BorderThickness="0"
BorderBrush="Transparent"
Background="{TemplateBinding Background}">
<Image x:Name="ButtonImage1" Source="/Training.Project.Demo;component/Images/Answer.PNG" Height="17" Width="17" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="Black" />
<Setter TargetName="border" Property="BorderThickness" Value="1" />
<Setter TargetName="ButtonImage1" Property="Source" Value="/Training.Project.Demo;component/Images/answer-hover.PNG" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
XAML:
<Button x:Name="AnswerButton" Style="{StaticResource hover2}" Grid.Column="0" VerticalAlignment="Center" HorizontalContentAlignment="Center" Width="60" Height="60" Background="Transparent" Click="AnswerButton_OnClick" BorderBrush="Transparent" BorderThickness="0" >
<Image Source="/Training.Project.Demo;component/Images/Answer.PNG" Stretch="UniformToFill"/>
</Button>
If you want a ContentPresenter, you should replace the its Content in the trigger:
<ControlTemplate TargetType="Button">
<Border Name="border"
BorderThickness="0"
BorderBrush="Transparent"
Background="{TemplateBinding Background}">
<ContentPresenter x:Name="cp" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="Black" />
<Setter TargetName="border" Property="BorderThickness" Value="1" />
<Setter TargetName="cp" Property="Content">
<Setter.Value>
<Image Source="/Training.Project.Demo;component/Images/answer-hover.PNG" Stretch="UniformToFill"/>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
The IsMouseOver property is never set to true if the Button is disabled.

WPF ToggleButton XAML styling

So I have two toggle buttons that I am trying to combine - sort of. So the first button toggles the images based on whether it IsChecked is true or false, but this button has a border around it that I can't get rid of.
The second toggle button doesn't have a border and doesn't blink when clicked, but it also doesn't change images based on it's state.
What I want is the best of both worlds. Change the image AND get rid of the border. I have tried exactly 23 things and none of them work.
Here is the code I am using:
<ToggleButton x:Name="changeButBorderedBlinky" Margin="0,12,194,0" Width="82" Height="82" Background="Transparent" Padding="-1" Focusable="false" VerticalAlignment="Top" HorizontalAlignment="Right">
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Content">
<Setter.Value>
<Border BorderThickness="0" >
<Image Source="images/buttonimages/back2.png" Stretch="Fill" />
</Border>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content">
<Setter.Value>
<Border BorderThickness="0" >
<Image Source="images/buttonimages/back.png" Stretch="fill" />
</Border>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
<ToggleButton x:Name="noChangeNoBorder" Margin="0,12,104,0" VerticalAlignment="Top" HorizontalAlignment="Right" Height="80" Width="80" >
<ToggleButton.Template>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border x:Name="border" >
<Image x:Name="img" Source="images/buttonimages/back2.png" />
</Border>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
Thanks for any help on this. It's driving me insane.
Your customization options are endless in either case. Have you ever tried Expression Blend? It comes along with Visual Studio 2013 Community (which is free to use) and it would let you customize either control any way you want.
Here, done using Expression Blend, no blink, no border, image swapping:
<ToggleButton x:Name="changeButBorderedBlinky" Margin="0,12,194,0" Width="82" Height="82" Background="Transparent" Padding="-1" Focusable="false" VerticalAlignment="Top" HorizontalAlignment="Right">
<ToggleButton.Template>
<ControlTemplate TargetType="{x:Type ButtonBase}">
<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
<ControlTemplate.Triggers>
<Trigger Property="Button.IsDefaulted" Value="True"/>
<Trigger Property="IsMouseOver" Value="True"/>
<Trigger Property="IsPressed" Value="True"/>
<Trigger Property="ToggleButton.IsChecked" Value="True"/>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="#FF838383"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ToggleButton.Template>
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Content">
<Setter.Value>
<Border BorderThickness="0" >
<Image Source="images/buttonimages/back2.png" Stretch="Fill" />
</Border>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content">
<Setter.Value>
<Border BorderThickness="0" >
<Image Source="images/buttonimages/back.png" Stretch="fill" />
</Border>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
Try to use slightly modified XAML pertinent to your first ToggleButton:
<ToggleButton x:Name="changeButBorderedBlinky"
Margin="0,12,194,0"
Width="82" Height="82"
Background="Transparent"
Padding="-1"
Focusable="false"
VerticalAlignment="Top" HorizontalAlignment="Right">
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Content">
<Setter.Value>
<Image Source="images/buttonimages/back2.png" Stretch="Fill" />
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content">
<Setter.Value>
<Image Source="images/buttonimages/back.png" Stretch="fill" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
You can also try to customize other properties, for eg:
<Setter Property="Background" Value="#FF1F3B53"/>
<Setter Property="Foreground" Value="#FF000000"/>
<Setter Property="BorderBrush" Value="Transparent">
For more styling options refer to: http://msdn.microsoft.com/en-us/library/cc296245%28v=vs.95%29.aspx
Hope this will help. Regards,

Graphics path minilanguage line aliasing

I am trying to draw a tick in a checkbox and for reason the aliasing doesn't seem to work, the lines are really jagged and don't look good at all. I am missing somthing?
<Style x:Key="{x:Type CheckBox}" TargetType="CheckBox">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="RenderOptions.EdgeMode" Value="Aliased"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<BulletDecorator Height="20" MinHeight="20">
<BulletDecorator.Bullet>
<Grid
Width="20"
Height="20">
<Border x:Name="Border"
CornerRadius="0"
Background="Black"
BorderThickness="0"
BorderBrush="Black"
Width="20"
Height="20" >
<Path
x:Name="CheckMark"
Stroke="White"
StrokeThickness="8"
Data="M 3,8 L 5,17,17,2"/>
</Border>
</Grid>
</BulletDecorator.Bullet>
<ContentPresenter Margin="0,0,0,0"
VerticalAlignment="Top"
HorizontalAlignment="Left"
RecognizesAccessKey="True" RenderOptions.EdgeMode="Aliased"/>
</BulletDecorator>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="false">
<Setter TargetName="CheckMark" Property="Visibility" Value="Collapsed"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Managed to fix this by setting the render options to unspecified.

How to create a WPF-tab control as chevron list?

I have a WPF tab control. but I would like to change the tab item style. The default style is square. I need to make it like a chevron list. Each block in that as hexagon.
EDIT:
Here's a quick example made with Kaxaml:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Style x:Key="chevronTabItemStyle" TargetType="{x:Type TabItem}">
<Setter Property="Foreground" Value="White" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<StackPanel Orientation="Horizontal" Margin="0,0,-7,0" Height="30">
<Path Data="M0,0 10,0 10,30 0,30 10,15"
Fill="{TemplateBinding Background}"/>
<Grid>
<Rectangle Fill="{TemplateBinding Background}" />
<TextBlock Text="{TemplateBinding Header}" Margin="10,5" VerticalAlignment="Center" />
</Grid>
<Path Data="M0,0 10,15 0,30"
Fill="{TemplateBinding Background}" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<Grid>
<TabControl ItemContainerStyle="{StaticResource chevronTabItemStyle}">
<TabItem Header="Design" Background="DarkSlateBlue" />
<TabItem Header="Plan" Background="DarkCyan" />
<TabItem Header="Build" Background="LightSkyBlue" />
<TabItem Header="Test" Background="SandyBrown" />
<TabItem Header="Evaluate" Background="SteelBlue" />
</TabControl>
</Grid>
</Page>
You will probably need to adjust a few properties, but it's roughly what you described...
Thomas Levesque your answer is beautiful!
There is a little problem with foreground color, move property into TextBlock prevent all tab to be colored White
In this way we can change the color of the header if properties IsEnable or Selected are valued.
<Style x:Key="TestNewTabStyle" TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<StackPanel Orientation="Horizontal" Margin="0,0,-7,0" Height="30">
<Path Data="M0,0 10,0 10,30 0,30 10,15" Fill="{TemplateBinding Background}"/>
<Grid >
<Rectangle Fill="{TemplateBinding Background}" />
<TextBlock Name="HeaderArrow" Text="{TemplateBinding Header}" Margin="15,5" VerticalAlignment="Center" Foreground="White"**/>
</Grid>
<Path Data="M0,0 10,15 0,30" Fill="{TemplateBinding Background}" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="HeaderArrow" Property="FontWeight" Value="Bold" />
<Setter TargetName="HeaderArrow" Property="Foreground" Value="Yellow" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="HeaderArrow" Property="Foreground" Value="DarkGray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Resources