WPF - Using Control Template just on one element - wpf

My first steps in WPF and C# and i don't get it to work... :(
I have an application with two grids inside one window. I have to change the style of the first grid, so i started reading and reached using ControlTemplate.
My Grid now looks as i wanted it. But i only want that the first grid looks this way. the second one on the same page should have another style.
Is it possible to bind the controltemplate only on one grid. Maybe by name or soemthing identifying?
My ControlTemplate Code for now i have written in window.resources looks:
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border
Name="Border"
Margin="0,0,0,0"
Background="Black"
BorderBrush="Black"
BorderThickness="0,2,0,0"
CornerRadius="0,0,0,0" >
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="0,0,0,20"
RecognizesAccessKey="True"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="BorderBrush" Value="#FF454E54" />
<Setter TargetName="Border" Property="Background" Value="#FF0A3651" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="BorderBrush" Value="White" />
<Setter TargetName="Border" Property="Background" Value="#FF454E54" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

You could give the Style or ControlTemplate an x:Key ( <Style x:Key="key" TargetType="{x:Type TabItem}"> ) and apply it to the element you want by setting the element's Style or Template property like this:
<TabItem Style="{StaticResource key}">
A Style without an x:Key is implicit and will be applied to all elements whose type matches the specified TargetType of the Style.

Instead of writing your template under Window.Resources do it under your Grid.Resources

Try this. All this is doing is setting the style of the TabItem directly.
<TabItem> <!-- This is your TabItem control -->
<TabItem.Style>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<!-- ControlTemplate here -->
</Controltemplate
</Setter.Value>
</Setter>
</Style>
</TabItem.Style>
</TabItem>

Related

WPF foreground inheritance

I created a simple style in WPF and I cannot figure out what case A works, but not case B.
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<ContentPresenter
TextBlock.Foreground="Red"
TextElement.Foreground="Yellow"
Content="{TemplateBinding Content}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Case A:
<Button Content="Test A"/> // background is Yellow
Case B:
<Button>
<TextBlock Text="Test B"/> // background is black
</Button>
I would like to create a style for a button that change text color of its content via the ContentPresenter.
Could someone explains what is missing to make case B to work?
(Ideally it should work with any content that have a Foreground property, not only TextBlocks).
Thanks in advance,
Thank you Clemens, but in fact I would like to change foreground of one part of the template only, not the foreground of the control itself. Button is just a simple example here.
I am using the ContentPresenter in triggers too:
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="#CCFFFFFF"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="#66FFFFFF"/>
</Trigger>
</ControlTemplate.Triggers>
Set the Button's Foreground property via another Setter:
<Style TargetType="Button">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<ContentPresenter Content="{TemplateBinding Content}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Alternatively, add a TextBlock Style to the ControlTemplate's Resources:
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ControlTemplate.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red"/>
</Style>
</ControlTemplate.Resources>
<Grid>
<ContentPresenter Content="{TemplateBinding Content}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Single Style for All Toggle Buttons but with Different Static Content

Static Resource Style
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1" Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="Red"></Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="Green" />
</Trigger>
</Style.Triggers>
</Style>
Toggle Button Code
<ToggleButton Grid.Row="3" Grid.Column="1" ToolTip="Toggle to Show and Hide Date" IsChecked="True" Cursor="Hand">
<ToggleButton.Style>
<Style TargetType="{StaticResource ToggleButton}">
<Setter Property="Content" Value="No Date" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="Date" />
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
But I'm unable to set the content getting error as Content is not recognized or inaccessible.
I'm not a frequent user of WPF.
Thanks
In your Toggle Button Code, Change
<Style TargetType="{StaticResource ToggleButton}">
to
<Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource {x:Type ToggleButton}}">
You can have a style defined for a control globally that is/may apply to all controls of that type, but when you have to give individual control some extra styling you can do that by creating a style within the control and base that style on the global style.
This basedOn can be done on style x:Type (as in my answer), or can be based on x:Name as well if you want to base it on a specific style.

How can I apply the same style for textbox and combobox in WPF?

I have made a BaseStyle, which looks like this:
<Style x:Key="BaseStyle" TargetType="{x:Type Control}">
<Setter Property="KeyboardNavigation.TabNavigation" Value="None" />
<Setter Property="AllowDrop" Value="true" />
<Setter Property="Background" Value="Transparent"></Setter>
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Setter Property="FontFamily" Value="Segoe UI" />
<Setter Property="FontSize" Value="12" />
<Setter Property="Padding" Value="8,5,3,3" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Control}">
<Grid>
<Border x:Name="BorderBase" Background="White" BorderThickness="1,1,1.4,1.4" BorderBrush="Silver" CornerRadius="4" />
<Label x:Name="TextPrompt" Content="{TemplateBinding Tag}" Visibility="Collapsed" Focusable="False" Foreground="Silver"></Label>
<ScrollViewer Margin="0" x:Name="PART_ContentHost" Foreground="{DynamicResource OutsideFontColor}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="BorderThickness" TargetName="BorderBase" Value="1,1,2.4,2.4"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate x:Name="InspectorErrorTemplate">
<StackPanel Orientation="Vertical">
<Border BorderBrush="Red" BorderThickness="1" CornerRadius="4">
<AdornedElementPlaceholder Name="adornerPlaceholder"/>
</Border>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And have used it this way to apply it to a textbox, which works fine:
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource BaseStyle}" />
Now I thought I can simply use the same style at a textbox of a combobox. So I thought I have to add something in this part:
<ControlTemplate x:Key="ComboBoxTextBox" TargetType="{x:Type TextBox}">
<Border x:Name="PART_ContentHost" Focusable="False" Background="{TemplateBinding Background}" />
<ControlTemplate.Triggers>
</ControlTemplate.Triggers>
</ControlTemplate>
However, I cannot add something like BasedOn="{StaticResource BaseStyle}" in the ControlTemplate to make e.g. the textbox to get a different border when it receives the focus (see IsFocused Trigger in the BaseStyle), or a red curved corner in case the validation is triggered... What am I doing wrong?
Hi you are working with different border color for different text-box that is the only problem here. There are several other options but I feel the following option is good to go.
You can create your own UserControl keeping a TextBox inside it. You can add a new DependencyProperty- BorderColor property in your UserControl. So that according to the BorderColor property value internally you can change the color of the border. So here you don't have to worry about multiple Style or any inheritance.
Isn't it?
The template for a TextBox is fundamentally different than the the template for a ComboBox. So you'll have to have different templates.
You can have one base style to define the shared properties (like Padding, FontFamily, etc.) without defining the Template property. Then make two more styles: one with TargetType set to TextBox; and the other with TargetType set to ComboBox. Each of these styles will be based on your base style and have additional definition for the template (and other properties that are not shared between the two controls).

Styling TabItem when populated with ItemsSource

I'm using a WPF Tabcontrol populated with a collection using Itemssource.
<TabControl x:Name="_tabControl" ItemsSource="{Binding TabViewModelList}">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding TabCaption}"/>
<Setter Property="Content" Value="{Binding TabContent}"/>
<Setter Property="IsSelected" Value="{Binding IsDefault}"/>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
Now I want to set my TabItem-style in my App.xaml(or other resourcefile) like this:
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border
Name="Border"
Background="LightBlue"
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="LightBlue" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="Border" Property="Background" Value="LightGray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
..but the ItemContainerStyle, of course overrides the controltemplate.
How do I combine these two so I can load my tabcontrol dynamically and still be able to style my TabItems the way I want to?
Ok... Solved my own problem. Pretty obvious..
Named my template
<Style TargetType="{x:Type TabItem}" x:Key="TabItemTemplate">
Added a BasedOn property like this:
<Style TargetType="TabItem" BasedOn="{StaticResource TabItemTemplate}">
But if I could combine them into one template please let me know...

Listview selection color

I'm playing around with wpf and I saw the following article:
WPF ListView Inactive Selection Color
I want to do something similar. I want to put a border around an a listviewitem when it is selected and i want to not change the background color. The reason I want this is I want a color coded listview and I still want to see the color when it's selected, but i want to know it's selected by it having a border around it.
Any ideas?
UPDATE:
I tried the below answer and it got me half way, it does put a border around the listviewitem but it overrides my background color. I can't get the right syntax i tried(Notice the BasedOn):
<Style x:Key="SourceListView" TargetType="{x:Type ListViewItem}">
<Setter Property="Background" Value="{Binding SourceType, Converter={StaticResource SourceGroupConverter}}"/>
</Style>
<Style x:Key="MyListViewItemStyle" TargetType="{x:Type ListViewItem}" BasedOn="{StaticResource SourceListView}" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border
x:Name="Border"
BorderBrush="Transparent"
BorderThickness="1">
<GridViewRowPresenter Columns="{TemplateBinding GridView.ColumnCollection}" Content="{TemplateBinding Content}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Border" Property="BorderBrush" Value="Black"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I then tried this:
<Style x:Key="MyListViewItemStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="Background" Value="{Binding SourceType, Converter={StaticResource SourceGroupConverter}}"/>
<Setter Property="Template">
...//Same as above
</Setter>
</Style>
Both attempts just set the background to white(or transparent I don't know). I know it's just syntax and I'd appreciate another nudge in the right direction :)
Change the ItemContainerStyle on the ListView to a style that doesn't change the background when an item is selected but instead changes the color of a border. Below is an example:
<Style x:Key="MyListViewItemStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="Background" Value="{Binding SourceType, Converter={StaticResource SourceGroupConverter}}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border
x:Name="Border"
BorderBrush="Transparent"
BorderThickness="1"
Background="{TemplateBinding Background}">
<GridViewRowPresenter Columns="{TemplateBinding GridView.ColumnCollection}" Content="{TemplateBinding Content}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Border" Property="BorderBrush" Value="Black"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And then use the style like this:
<ListView ItemContainerStyle="{StaticResource MyListViewItemStyle}">
...
</ListView>

Resources