WPF Set controltemplate for only first level - wpf

I have a style for tabcontrol :
<Style TargetType="{x:Type TabControl}" x:Key="CloseableTabControl">
<Style.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
this have effect for all tabitem contained into tabcontrol, including item of child tabcontrol.
I want that only first level tabitems have applicated the style.
How I can accomplish this?

Since you haven't set value x:Key for the TabItem style, hence it gets applied to all TabItems found in the Visual Tree. In case you want the style to be applied to only specific TabItems you need to set the x:Key value -
<Style TargetType="{x:Type TabItem}"
x:Key="TabItemStyle">
And wherever you want the Style to be applied, you have to use StaticResource-
<TabItem Style="{StaticResource TabItemStyle}"/>

Related

WPF Styles and Polymorphism

I know I'm a pervert, but I am very curious, is there a way to make custom controls to seek for it's base class style first, and then it's own.
Why I'm asking: I have some TreeView derived controls with custom item templates. I apply those templates, then I have a base style. Later I might apply some color palette. At the last step I have a problem. I need to apply 2 styles. PVStructuralTree is derived from TreeView it has some DependencyProperty DataTemplates that get inserted into resources in code.
PVStructuralTreeView
EmploeeTemplate
... more templates
Default style for PVStructuralTreeView:
<Style x:Key="DefaultPVStructuralTreeView" TargetType="{x:Type c:PVStructuralTreeView}" BasedOn="{StaticResource DefaultTreeView}">
<Setter Property="EmploeeTemplate"><!-- This get inserted inro Resources in code -->
<Setter.Value>
<DataTemplate DataType="{x:Type s:Emploee}">
...
</DataTemplate>
</Setter.Value>
</Setter>
... Lots of them here
</Style>
<Style TargetType="{x:Type c:PVStructuralTreeView}" BasedOn="{StaticResource DefaultPVStructuralTreeView}"/>
Default style for a TreeView (it's pretty big, so I won't post it here):
<Style TargetType="{x:Type TreeView}" BasedOn="{StaticResource DefaultTreeView}"/>
In color template.xaml file I'd like to have this + some magic to apply both styles at the same time (from Generic.xaml and themed one):
<Style x:Key="ThemedTreeView" TargetType="{x:Type TreeView}" BasedOn="{StaticResource DefaultTreeView}">
...
</Style>
<Style TargetType="{x:Type c:PVStructuralTreeView}" BasedOn="{StaticResource ThemedTreeView}"/>
But it just overwrites generic.xaml styles. I want it to add to it.
Now I'm doing this way:
<Style x:Key="ThemedPVStructuralTreeView" TargetType="{x:Type c:PVStructuralTreeView}" BasedOn="{StaticResource DefaultPVStructuralTreeView}">
... CopyPaste from ThemedTreeView ...
</Style>
<Style TargetType="{x:Type c:PVStructuralTreeView}" BasedOn="{StaticResource ThemedPVStructuralTreeView}"/>
Does anyone knows the way how to reuse the ThemedTreeView style here?
You can base a Style on Another (one only!) Style using the BasedOn property and override specific properties, but you cannot base a DataTemplate or a ControlTemplate on another template. This is not supported. A template must be defined as a whole:
WPF: Is there a way to override part of a ControlTemplate without redefining the whole style?

Stop child from inheriting parent Style in TabControls

In my WPF application i have a TabControl that i am binding to a style i created:
On my View:
<TabControl Grid.Row="6" Style="{DynamicResource SideBarTabControl}">
On a separate ResourceDictionary:
<Style x:Key="SideBarTabControl" TargetType="{x:Type TabControl}" BasedOn="{StaticResource {x:Type TabControl}}" >
<Setter Property="FontSize" Value="{DynamicResource TitleFontSize}"/>
</Style>
So far so good, things work as expected. The problem is that now all the children of this TabControl, such as a ListView inside a TabItem, is also getting the same FontSize as the TabControl, instead of the default.
I thought that by specifying TargetType="{x:Type TabControl}" i would stop the style from being applied to children of different types. What i'm looking for is to actually stop it from affecting EVERYTHING BUT the component that explicitly inherited the style. So how can this be done? I think i am missing something simple...
If i override the font size in my ListView it works, but this means i have to do it for every child, which might become very cumbersome.
I have read this and other questions but i can't find the answer i'm looking for:
Is it possible to set a style in XAML that selectively affects controls?
This is working for me. The part that's doing the work is TabControl.ItemContainerStyle. It applies a font size only to the header content.
<TabControl>
<TabControl.ItemContainerStyle>
<Style
TargetType="TabItem"
BasedOn="{StaticResource {x:Type TabItem}}"
>
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<ContentControl
TextElement.FontSize="20"
Content="{Binding Header, RelativeSource={RelativeSource AncestorType=TabItem}}"
/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.ItemContainerStyle>
<TabItem Header="Foo">
<Label Content="Bar" />
</TabItem>
<TabItem Header="Baz">
<Label Content="Bar" />
</TabItem>
</TabControl>
You cannot stop it, it's not the style causing this unwanted trickle-down effect you want rid of; it's just how WPF controls work.
What you will have to do to stop this is write another style for your tab items to intercept the one being inherited from the TabControl.
I suggest writing this style inside your existing TabControl style, inside the Style.Resources tag like so:
<Style x:Key="SideBarTabControl" TargetType="{x:Type TabControl}" BasedOn="{StaticResource {x:Type TabControl}}" >
<Style.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="FontSize" Value="9001"/>
<!-- Any other setters you want for TabItems -->
</Style>
</Style.Resources>
<Setter Property="FontSize" Value="{DynamicResource TitleFontSize}"/>
</Style>
By making a style inside your other style's resources, it will be carried with it, and by not specifying any x:Key for the TabItem style - it will apply it to any TabItem not ordered to have a specific style, becoming the default style for any TabItem you make inside the TabControl now.

WPF ControlTemplate breaks style

The stuff that does work
I need to style controls of a certain type that are children of a StackPanel. I'm using:
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type TextBlock}">...</Style>
</StackPanel.Resources>
<TextBlock ...>
...
</StackPanel>
And this works fine! Each TextBlock looks to the resources of it's parent (the StackPanel) to find out how it should be styled. It doesn't matter how far down you nest the TextBlock down a StackPanel... if it doesn't find a style in its direct parent, it will look at its parent's parent and so on, until it finds something (in this case, the style that was defined in ).
The stuff that doesn't work
I ran into a problem when I nested a TextBlock inside a ContentControl, which had a Template (see code below). The ControlTemplate seems to disrupt the way a TextBlock retrieves its style from its parents, grandparents,...
The use of a ControlTemplate effectively seems to knock out cold the TextBlock's means of finding its rightful style (the one in StackPanel.Resources). When it encounters a ControlTemplate, it stops looking for its style in the resources up the tree, and instead defaults to the style in MergedDictionaries of the Application itself.
<StackPanel Orientation="Vertical" Background="LightGray">
<StackPanel.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Green" />
</Style>
</StackPanel.Resources>
<TextBlock Text="plain and simple in stackpanel, green" />
<ContentControl>
<TextBlock Text="inside ContentControl, still green" />
</ContentControl>
<ContentControl>
<ContentControl.Template>
<ControlTemplate TargetType="{x:Type ContentControl}">
<StackPanel Orientation="Vertical">
<ContentPresenter />
<TextBlock Text="how come this one - placed in the template - is not green?" />
</StackPanel>
</ControlTemplate>
</ContentControl.Template>
<TextBlock Text="inside ContentControl with a template, this one is green as well" />
</ContentControl>
</StackPanel>
Is there a way - besides duplicating the Style in StackPanel.Resources to ControlTemplate.Resources - to make the TextBlock inside that ControlTemplate find the defined style?
Thanks...
WPF considers ControlTemplates to be a boundry, and will not apply implicit styles (styles without an x:Key) inside of templates.
But there is one exception to this rule: anything that inherits from Control will apply implicit styles.
So you could use a Label instead of a TextBlock, and it would apply the implicit style defined further up your XAML hierarchy, however since TextBlock inherits from FrameworkElement instead of Control, it won't apply the implicit style automatically and you have to add it manually.
My most common way to get around this is to add an implicit style in the ControlTemplate.Resources that is BasedOn the existing implicit TextBlock style
<ControlTemplate.Resources>
<Style TargetType="{x:Type TextBlock}"
BasedOn="{StaticResource {x:Type TextBlock}}" />
<ControlTemplate.Resources>
Other common ways of getting around this are:
Place the implicit style in <Application.Resources>. Styles placed here will apply to your entire application, regardless of template boundaries. Be careful with this though, as it will apply the style to TextBlocks inside of other controls as well, like Buttons or ComboBoxes
<Application.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Green" />
</Style>
</Application.Resources>
Use a Label instead of a TextBlock since it's inherited from Control, so will apply implicit Styles defined outside the ControlTemplate
Give the base style an x:Key and use it as the base style for an implicit TextBlock styles inside the ControlTemplate. It's pretty much the same as the top solution, however it's used for base styles that have an x:Key attribute
<Style x:Key="BaseTextBlockStyle" TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Green" />
</Style>
...
<ControlTemplate.Resources>
<Style TargetType="{x:Type TextBlock}"
BasedOn="{StaticResource BaseTextBlockStyle}" />
<ControlTemplate.Resources>

Why does x:Key unapply my TabItem Style

I am trying to make a custom style for a TabItem Header. I got it to work by accident.
this fails:
<Style TargetType="{x:Type TabItem}" x:Name="TabHeader3" x:Key="test">
but this works
<Style TargetType="{x:Type TabItem}" x:Name="TabHeader3">
What's going on?
The first Style you have defined is an "explicit" Style, so you must explicitly use it like so:
<TabItem Style="{StaticResource test}" />
The second Style you have defined is an "implicit" Style. So it will be applied to all TabItem controls below it in the visual/logical tree, or to all TabItem controls if it's defined in the application resources.
Your second Style is equivalent to:
<Style TargetType="{x:Type TabItem}" x:Name="TabHeader3" x:Key="{x:Type TabItem}">
So the key is the Type of the object to which it should be applied.
If a TabItem has a Style explicitly defined (like I show above), then any implicit Styles will not be used. Also, if you have two implicit Styles defined, then the closest one wins. So here:
<Window>
<Window.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Background" Value="Red" />
</Style>
</Window.Resources>
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Background" Value="Blue" />
</Style>
</Grid.Resources>
...
<TabItem ... />
...
</Grid>
</Window>
The Blue Style will take precedence over the Red Style.
Finally, you generally don't need to include x:Name on your Styles.
If you add the style to a resource dictionary without a key then the style gets applied to all TabItems that are within the scope of the resource dictionary by default. If you add a Key to the style then you need to manually set the Style

Wpf Combobox Rounded Corners

How can i make a combobox edges rounded..?.I have tried in blend,but no success till now..Any input will be highly helpfull
You need to create a custom Style in XAML for your ComboBox in which the outer container is a border with rounded corners. In this particular example, it's a default style that will be blanket applied throughout your application. The content of the control and ContentPresenter must still be declared within the Border.
<Style TargetType="{x:Type ComboBox}">
...
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Border CornerRadius="5">
...
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Resources