Is there a way I can reuse Styles for more than 1 TargetType eg. ComboBox and TextBox
<Style TargetType="ComboBox, TextBox" />
is there such a thing? Or is the only way duplicate the style and target each style to differnt types?
You can't (if I'm not mistaken).
But what you may do in order to avoid copy-paste is to create a BaseStyle with a key and then create two styles for ComboBox and TextBox which are BasedOn the BaseStyle. smth like that:
<Style x:Key="BaseStyle" TargetType="{x:Type Control}">
<Setter ... />
</Style>
<Style BasedOn="{StaticResource BaseStyle }" TargetType="{x:Type ComboBox }" />
<Style BasedOn="{StaticResource BaseStyle }" TargetType="{x:Type TextBox}" />
Instead of this you can provide targettype as control and define setter proeprties of control and apply that style to textbox and combox.
Related
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?
Why do my Radiobutton not look like a togglebutton?
Take a look at the code
<Style x:Key="ButtonBaseStyle" TargetType="{x:Type ButtonBase}">
<Setter Property="Height" Value="100" />
</Style>
<Style BasedOn="{StaticResource ButtonBaseStyle}" TargetType="{x:Type Button}" />
<Style BasedOn="{StaticResource ButtonBaseStyle}" TargetType="{x:Type ToggleButton}" />
<Style BasedOn="{StaticResource {x:Type ToggleButton}}" TargetType="{x:Type RadioButton}" />
<StackPanel>
<Button>Button</Button>
<ToggleButton>Toggle</ToggleButton>
<RadioButton>Radio</RadioButton>
</StackPanel>
If I remove the buttonbase style it works
The looks of your RadioButton is not as ToggleButton cause of you have now changed the style hierarchy of ButtonBase->ToggleButton->RadioButton (the order in which styles and templates are overwritten in derived classes of WPF).
Your new hierarchy of style gives the most priority to the style of ButtonBase. So you have a new ToggleButton style that is derived from a ButtonBase and then you overwrite the RadioButton style with that. So noone can tell you for sure which properties have you overwritten and which will be the final set of properties.
To understand this change the XAML as following:
<Style BasedOn="{StaticResource {x:Type ToggleButton}}" TargetType="{x:Type ToggleButton}" />
<Style BasedOn="{StaticResource {x:Type ToggleButton}}" TargetType="{x:Type RadioButton}" />
and now see the look & feel of your RadioButton.
I'm not clarifying what is exactly happened and why your ToggleButton is not affected so much.
But as I said it's all about the style hierarchy which is build for a control at last just before rendering on the UI.
I want to use custom theme in my application and as far as I know I can accomplish this by using resource dictionary and referencing it in App.xaml. Styles would override the defaults like this:
<Style TargetType="{x:Type Label">
<Setter Property="Foreground" Value="Green" />
</Style>
Now as I guess the default Label style is overriden with same values but all my label fonts are green. The problem starts when I want to style one label somewhere again. When I want to change some other property in my Grid like this
<Grid.Resources>
<Style TargetType="{x:Type Label">
<Setter Property="FontSize" Value="28" />
</Style>
</Grid.Resources>
All labels inside my grid are losing their foreground color and have default one again (didn't I override defaults in previous step?). After some tries I found out that to do this properly i have to add another property to Style declaration BasedOn={StaticResource {x:Type Label}}" and it works. This is kind of weird for me because now I will have to repeat same BasedOn code in whole app and this is not how styling works - this should be done automatically! For example in HTML + CSS styles are inherited and merged and in WPF they are replaced...
Notice that when I don't use any styles controls still get their look from somehwere (System Themes?). How can I tell them to look for defaults somewhere else so without any additional code on styles they will think that they should be green by default?
Is there any way I can automate setting BasedOn property? Or maybe there is a better to do this overally?
I had the same problem. I used Zack's answer and improved it like following so if you don't specify a style the overridden default is still taken in account. It's basically what you would have done but just once in the ResourceDictionary.
<Window x:Class="TestWpf.RandomStuffWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Random Stuff Window">
<Window.Resources>
<ResourceDictionary>
<!-- Default Label style definition -->
<Style TargetType="{x:Type Label}">
<Setter Property="Foreground" Value="Green" />
</Style>
<!-- Extending default style -->
<Style TargetType="{x:Type Label}"
x:Key="LargeGreenForegroundLabel"
BasedOn="{StaticResource {x:Type Label}}">
<Setter Property="FontSize" Value="28" />
</Style>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<Button Click="Button_Click">Click</Button>
<Label Content="GreenForegroundLabel" /> <!-- Uses default style -->
<Label Style="{StaticResource LargeGreenForegroundLabel}"
Content="LargeGreenForegroundLabel" />
</StackPanel>
</Window>
Wpf has different levels of styles, that are applied in order of global > local. A style set directly on a control will override a style set globally, like in your example. I was trying to find a list of all the different places that a control looks for its styles but I cannot find one at the moment. As far as I know, you will have to use the BasedOn property to inherit a style and not completely override the properties of that style with the style you set locally.
Here is an example of a resource dictionary that has styles based on another style, so that you don't have do repeat the BasedOn binding over and over, you can just set the style on the specific element you want to have that style.
<Window x:Class="TestWpf.RandomStuffWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Random Stuff Window">
<Window.Resources>
<ResourceDictionary>
<Style TargetType="{x:Type Label}"
x:Key="GreenForegroundLabel">
<Setter Property="Foreground" Value="Green" />
</Style>
<Style TargetType="{x:Type Label}"
x:Key="LargeGreenForegroundLabel"
BasedOn="{StaticResource GreenForegroundLabel}">
<Setter Property="FontSize" Value="28" />
</Style>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<Button Click="Button_Click">Click</Button>
<Label Style="{StaticResource GreenForegroundLabel}"
Content="GreenForegroundLabel" />
<Label Style="{StaticResource LargeGreenForegroundLabel}"
Content="LargeGreenForegroundLabel" />
</StackPanel>
</Window>
I want to set consistent margins throughout all controls within an entire view. I currently use XAML:
<Window.Resources>
<Thickness x:Key="ConsistentMargins">0,10,0,0</Thickness>
</Window.Resources>
<!-- ... -->
<!-- ... -->
<!-- ... -->
<MyControl1 Margin="{StaticResource ConsistentMargins}">
<MyControl2 Margin="{StaticResource ConsistentMargins}">
<MyControl3 Margin="{StaticResource ConsistentMargins}">
Is there a way to set a default layout style for controls to avoid the above repeated code shown above?
You can create your own style with TargetType and this style will be assigned to all object of type which you specified in TargetType. But in this case your created style will be applied only for speciefied type of object, but not for derived type.
E.g. you can create style for all buttons like this:
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="0,10,0,0" />
</Style>
I think that this makes sense that style is not applied from base class, because I want say "My all buttons looks like...", but I want not say "Everything looks like...".
You may create a base default style, perhaps for FrameworkElement, and let the default styles for other element types extend the base style:
<Window.Resources>
<Style TargetType="FrameworkElement">
<Setter Property="Margin" Value="0,10,0,0"/>
</Style>
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type FrameworkElement}}"/>
<Style TargetType="TextBox" BasedOn="{StaticResource {x:Type FrameworkElement}}"/>
<Style TargetType="Label" BasedOn="{StaticResource {x:Type FrameworkElement}}"/>
...
</Window.Resources>
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