i've seen that is common to put a ControlTemplate inside a Style as in the following example
<Style x:Key="roundbutton" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
instead of just defininig the control template as a resurce
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
What are the advantages of defining the ControlTemplate inside a Style?
Related
I make use of a resource dictionary with all my styles, icons and more.
Now I'd like to add my own titlebar implementing the title of the solution, my image and a ContentPresenter.
When using the WindowStyle I'd like to add application specific items inside this ContentPresenter, but I don't know how to proceed.
This is my WindowStyle. Inside the Grid you'll find the ContentPresenter I'd like to fill.
<Style TargetType="{x:Type Window}" x:Key="tkDarkWindowStyle">
<Setter Property="AllowsTransparency" Value="True"></Setter>
<Setter Property="Foreground" Value="{StaticResource tkBrandBlueBrush}"></Setter>
<Setter Property="Background" Value="{StaticResource exQuiteDarkBrush}"></Setter>
<Setter Property="WindowStyle" Value="None"></Setter>
<Setter Property="BorderThickness" Value="0"></Setter>
<Setter Property="BorderBrush" Value="{StaticResource exQuiteDarkBrush}"></Setter>
<Setter Property="WindowChrome.WindowChrome">
<Setter.Value>
<WindowChrome CaptionHeight="80" />
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Window">
<DockPanel LastChildFill="True">
<Border Background="{TemplateBinding Background}" DockPanel.Dock="Top"
Height="80" x:Name="titlebar">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<DockPanel Grid.Column="0">
<Path DockPanel.Dock="Left" Margin="10" Stretch="Uniform" Fill="{TemplateBinding Foreground}" Data="{Binding Source={StaticResource tkPrimaryLogo}}" VerticalAlignment="Center">
</Path>
<Label Content="{TemplateBinding Title}" Foreground="{TemplateBinding Foreground}" Margin="10" DockPanel.Dock="Left" FontSize="26" VerticalAlignment="Center"/>
</DockPanel>
<ContentPresenter Grid.Column="1"/>
</Grid>
</Border>
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1" Padding="4">
<ContentPresenter/>
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I used the style like this and tried to edit the template and add for example some buttons to the titlebar.
<Window.Resources>
<Style TargetType="{x:Type Window}" x:Key="newWindow" BasedOn="{StaticResource tkDarkWindowStyle}">
<!--here add application specific items? -->
</Style>
</Window.Resources>
How can I use the WindowStyle in my application and add specific items to the space i left at the titlebar?
Since the Window only has a single Content property, it makes no sense to include more than one <ContentPresenter /> element in the ControlTemplate.
You may want to create a custom class that inherits from Window and adds a dependency property called "TitleBarContent" or something. You can then add a ContentControl to the template that binds to this property:
<ContentControl Content="{TemplateBinding TitleBarContent}" />
You can set the value of the dependency property in a style setter as usual:
<Style TargetType="{x:Type local:YourWindowClass}" x:Key="newWindow" BasedOn="{StaticResource tkDarkWindowStyle}">
<Setter Property="TitleBarContent">
<Setter.Value>
<TextBlock>title...</TextBlock>
</Setter.Value>
</Setter>
</Style>
Here is a button which I styled, but I realized that there is no way for someone who uses the application to notice when button is mouse over / selected or something like that?
I just want some kind of notification when button is selected or whatever?
Any kind of solution will be acceptable for me so in case button is mouse hovered, or in case button is selected to notice user
that is that button!
Here is my current button:
<Button x:Name="btnOk"
SnapsToDevicePixels="True"
UseLayoutRounding="True"
IsDefault="True"
Grid.Row="2"
Grid.Column="1"
FontSize="15"
Width="140"
BorderThickness="1"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Foreground="#0091EA"
Background="White"
Content="Ok!"
BorderBrush="#0091EA" Margin="5,10,0,10" HorizontalAlignment="Left" Click="btnPotvrdi_Click">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="BlueViolet"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</ControlTemplate>
</Button.Template>
</Button>
Specify the default background (White) in the Style and your trigger will work as expected:
<Button x:Name="btnOk"
SnapsToDevicePixels="True"
UseLayoutRounding="True"
IsDefault="True"
Grid.Row="2"
Grid.Column="1"
FontSize="15"
Width="140"
BorderThickness="1"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Foreground="#0091EA"
Content="Ok!"
BorderBrush="#0091EA" Margin="5,10,0,10" HorizontalAlignment="Left" Click="btnPotvrdi_Click">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="White" />
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Background" Value="Green"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="BlueViolet"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</ControlTemplate>
</Button.Template>
</Button>
A "local" value takes precedence over a value set by a Setter in a Style: https://msdn.microsoft.com/en-us/library/ms743230(v=vs.110).aspx
I have a Viewbox:
<Viewbox x:Key="SampleViewbox" >
<Grid>
<Ellipse Stroke="#e2e2e0" StrokeThickness="6" Fill="#d5273e" Width="128" Height="128"/>
</Grid>
</Viewbox>
I then include this in a Style like:
<Style x:Key="SampleStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="Transparent" >
<ContentPresenter Content="{StaticResource SampleViewbox}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now I created many buttons with SampleStyle
<Grid>
<StackPanel>
<Button Style="{StaticResource SampleStyle}" Height="50" Width="50"></Button>
<Button Style="{StaticResource SampleStyle}" Height="80" Width="80"></Button>
<Button Style="{StaticResource SampleStyle}" Height="20" Width="20"></Button>
</StackPanel>
</Grid>
However, Only one button has the Ellipse (viewbox)
How can I make all the buttons have/show the ellipse??
Viewbox is FrameworkElement which cannot belong to multiple parents. Every time buttons request a resource {StaticResource SampleViewbox} they get the same instance.
to change that behavior add x:Shared="False" attribute
<Viewbox x:Key="SampleViewbox" x:Shared="False">
I think a good approach is to use DataTemplate.
So you will have
<DataTemplate x:Key="SampleViewbox">
<Viewbox>
<Grid>
<Ellipse
Width="128"
Height="128"
Fill="#d5273e"
Stroke="#e2e2e0"
StrokeThickness="6" />
</Grid>
</Viewbox>
</DataTemplate>
And for style
<Style x:Key="SampleStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="Transparent">
<ContentPresenter ContentTemplate="{StaticResource SampleViewbox}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Setting the x:Shared attribute of the ViewBox to false as suggested by #ASh will indeed work but why don't you just include the ViewBox in the ControlTemplate like this?
<Style x:Key="SampleStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="Transparent" >
<Viewbox>
<Grid>
<Ellipse Stroke="#e2e2e0" StrokeThickness="6" Fill="#d5273e" Width="128" Height="128"/>
</Grid>
</Viewbox>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
A template is a template and a control instance is an instance.
I am designing my own tooltip in SilverLight 5 and need to pass several values to it when displaying it.
Here is the Style:
<Style x:Key="TooltipStyle" TargetType="ToolTip">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Border BorderBrush="Blue" BorderThickness="2" Background="White">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Var Number: "></TextBlock>
<ContentPresenter x:Name="Content1"
Content="{TemplateBinding Content}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</StackPanel>
<StackPanel Grid.Row="1">
<TextBlock Text="Last Update Date: " />
<ContentPresenter x:Name="Content2"
Content="{TemplateBinding Content}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</StackPanel>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I am applying the style like so:
var customTooltip = new ToolTip
{
Style = (Style)Resources["TooltipStyle"],
Content = questions.Number[c]
};
ToolTipService.SetToolTip(textbox, customTooltip);
There is only one 'Content' property there, but I need to pass something to 'Content2' as well. (Please note the content is gathered as we do a 'for' loop.)
So the image that comes up, instead of having one variable, can have both the Var Number and the Last Update Date. Reputation too low to post image, here is the final look of the tooltip to give you an idea:
http://imgur.com/HYBbXMN
So that's the situation.
Now I am wondering if I can expose a second Content property? Or perhaps there is a smarter and better way to style the tooltip to meet my needs?
Please note this example requires two values (or 'Content') to be displayed but tooltip will expand to require more.
I will appreciate any ideas.
So to make it easier on ya, personally I just leverage things already available for that type of thing. Like for example using Tag to piggy back that sort of thing into the template.
An example (with some additions for setters and stuff you'll probably want to omit or change) like;
<Style x:Key="NiftyToolTipStyle" TargetType="ToolTip">
<Setter Property="FontFamily" Value="{StaticResource FontFamily}" />
<Setter Property="FontSize" Value="{StaticResource FontSize}" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="Background" Value="White" />
<Setter Property="Padding" Value="3" />
<Setter Property="BorderThickness" Value="1,2" />
<Setter Property="BorderBrush" Value="Blue" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Border x:Name="Root"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="1"
Padding="{TemplateBinding Padding}"
Cursor="{TemplateBinding Cursor}">
<Border.Effect>
<DropShadowEffect Opacity="0.35" ShadowDepth="3" />
</Border.Effect>
<TextBlock>
<Run Text="{TemplateBinding Tag, StringFormat='Var Number: \{\0}'}"/>
<LineBreak/>
<Run Text="{TemplateBinding Content, StringFormat='Last Update Date: \{\0}'}"/>
</TextBlock>
<!--
<ContentPresenter Margin="{TemplateBinding Padding}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Cursor="{TemplateBinding Cursor}" />
-->
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This way you can just pass in one value to Content and another to Tag and you're good. You could also easily do other stuff, there's multiple options. Hope this helps, Cheers
I've been stylizing a TabControl in WPF XAML (.NET 4), all i can do is style a tab based on triggers or identically style them all. Is there any way that only the first tab is stylized different while the other tabs are stylized different than the first tab but the same as each other (a.k.a using the Tab Index to stylize a TabItem).
Thank you.
You can use AlternationCount and AlternationIndex:
<TabControl AlternationCount="{Binding Path=Items.Count,RelativeSource={RelativeSource Self}}">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex"
Value="0"> <!-- First item -->
<Setter Property="FontWeight"
Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
</TabControl.ItemContainerStyle>
<TabItem Header="First"/>
<TabItem Header="Second"/>
<TabItem Header="Third"/>
<TabItem Header="Fourth"/>
</TabControl>
If you want to change the background color of just selected tab item then use that kind of style and apply that style to tab Item.
<Style TargetType="{x:Type TabItem}" x:Key="TabItemStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border Name="Border" Background="Red" BorderBrush="#FF1467AF"
BorderThickness="1"
Margin="0,0,5,0" CornerRadius="8,8,0,0" SnapsToDevicePixels="True">
<TextBlock FontFamily="Arial" FontWeight="Bold" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center" Name="TextBlock" Foreground="White">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Header" Margin="12,2,12,2"/>
</TextBlock>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="Yellow"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But if you want to just change the background color of First tab item then define two styles and apply one to first tab item and second one to other
Style for tab item 1:
<Style TargetType="{x:Type TabItem}" x:Key="TabItemStyleForFirst">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border Name="Border" Background="Red" BorderBrush="#FF1467AF"
BorderThickness="1"
Margin="0,0,5,0" CornerRadius="8,8,0,0" SnapsToDevicePixels="True">
<TextBlock FontFamily="Arial" FontWeight="Bold" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center" Name="TextBlock" Foreground="White">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Header" Margin="12,2,12,2"/>
</TextBlock>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Style for other tab items:
<Style TargetType="{x:Type TabItem}" x:Key="TabItemStyleForOther">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border Name="Border" Background="Yellow" BorderBrush="#FF1467AF"
BorderThickness="1"
Margin="0,0,5,0" CornerRadius="8,8,0,0" SnapsToDevicePixels="True">
<TextBlock FontFamily="Arial" FontWeight="Bold" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center" Name="TextBlock" Foreground="White">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Header" Margin="12,2,12,2"/>
</TextBlock>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>