How to target all controls (WPF Styles) - wpf

Can I specify a style that applies to all elements? I tried
<Style TargetType="Control">
<Setter Property="Margin" Value="0,5" />
</Style>
But it did nothing

The Style you created is only targeting Control and not elements that derive from Control. When you don't set the x:Key it's implicitly set to the TargetType, so in your case x:Key="{x:Type Control}".
There isn't any direct way to specify a Style that targets all elements that derive from the TargetType of the Style. You have some other options.
If you have the following Style
<Style x:Key="ControlBaseStyle" TargetType="{x:Type Control}">
<Setter Property="Margin" Value="50" />
</Style>
You can target all Buttons for example
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource ControlBaseStyle}"/>
or use the style directly on any element, e.g. Button
<Button Style="{StaticResource ControlBaseStyle}" ...>

As Fredrik Hedblad answered you can effect all elements that inherited from control.
But you can't apply style for textblock and button with the same style for example.
to do that:
<Style x:Key="DefaultStyle" TargetType="{x:Type FrameworkElement}">
<Setter Property="Control.Margin" Value="50"/>
</Style>
<Style TargetType="TextBlock" BasedOn="{StaticResource DefaultStyle}"/>
<Style TargetType="Button" BasedOn="{StaticResource DefaultStyle}"/>

Related

Wpf - Create a Style in a resource dictionary that sets properties of children of a grid [duplicate]

Is it possible to define a ResourceDictionary in a Style?
For example, suppose I wanted to have two different Styles for StackPanels and in one I want all the buttons to be blue and the other I want them to be red. Is this possible?
Something like
<Style x:Key="RedButtonsPanel" TargetType="{x:Type StackPanel}">
<Setter Property="Orientation" Value="Horizontal" />
<Setter Property="StackPanel.Resources">
<Setter.Value>
<ResourceDictionary>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Red" />
</Style>
</ResourceDictionary>
</Setter.Value>
</Setter>
</Style>
The above code fails with an error about the Property value of a Setter cannot be null (even though it's obviously not null).
I can do something like
<ResourceDictionary x:Key="RedButtons">
<Style TargetType="{x:Type Button}">
<Setter Property="Width" Value="100" />
<Setter Property="Background" Value="Red" />
</Style>
</ResourceDictionary>
<StackPanel Resources={StaticResource RedButtons} />
However I was wondering if there was a way to merge the ResourceDictionary into the style.
Try adding the Style(s) for each TargetType to the DockPanel Style.Resources.
I did something similar with a DockPanel Style. Wanted all Buttons or Separators added to the DockPanel to get styled in a consistent manner.
Here's a sample:
<Style x:Key="DockPanelToolBarStyle" TargetType="{x:Type DockPanel}">
<Style.Resources>
<Style TargetType="Button" BasedOn="{StaticResource ButtonToolBarStyle}" />
<Style TargetType="Separator" BasedOn="{StaticResource SeparatorToolBarStyle}" />
</Style.Resources>
<Setter Property="Height" Value="45"/>
<Setter Property="Background" Value="{StaticResource ToolBarBrush}"/>
</Style>
StackPanel.Resources is not a DependencyProperty and therefore I don't believe you will be able to set that property within the style.

Can't set style with TargetType Shape

I am trying to set the Shape.Stroke property for several shape types using a style in WPF.
<Style.Resources>
<Style TargetType="{x:Type Polyline}">
<Setter Property="Stroke" Value="White"/>
</Style>
<Style TargetType="{x:Type Path}">
<Setter Property="Stroke" Value="White"/>
</Style>
<Style TargetType="{x:Type Ellipse}">
<Setter Property="Stroke" Value="White"/>
</Style>
...
</Style.Resources>
It does not seem possible to just set the style for the base class Shape.
<Style.Resources>
<Style TargetType="{x:Type Shape}">
<Setter Property="Stroke" Value="White"/>
</Style>
</Style.Resources>
Is there no better way than the first option I listed?
When WPF searches for an implicit Style, it looks for a resource whose key matches the DefaultStyleKey of the element to be styled. The convention in WPF is that every control T overrides the DefaultStyleKey to be typeof(T). WPF will not attempt to fall back to the base type's style key if a match is not found.
Ellipse, for example, has an implied[1] default style key of typeof(Ellipse), so WPF will only attempt to resolve an implicit style with that key; a resource keyed on typeof(Shape) will not be applied.
If you want to use implicit styles, you will need to define an implicit Style per concrete type. However, those styles may inherit setters and triggers from a common base Style:
<Style x:Key="x" TargetType="{x:Type Shape}">
<Setter Property="Stroke" Value="Black"/>
</Style>
<Style TargetType="Ellipse" BasedOn="{StaticResource x}" />
<Style TargetType="Path" BasedOn="{StaticResource x}" />
<Style TargetType="Polyline" BasedOn="{StaticResource x}" />
Note that while implicit styles for base types will not be applied automatically, they are still compatible, and they can be applied explicitly:
<Style x:Key="StrokedShape" TargetType="{x:Type Shape}">
<Setter Property="Stroke" Value="Black"/>
</Style>
<!-- ... -->
<Ellipse Style="{StaticResource StrokedShape}" />
[1] Some WPF elements do not override DefaultStyleKey. Shape and its subclasses are among them. In such cases, WPF assumes the default convention.

WPF Style BasedOn parent Style in current context

Say, I have a default style for a TextBox 'TextBoxStyleBase'.
I then define a DataGrid style which has an own TextBox style BasedOn that Base-style, defining another Border Color.
In some place inside a DataGrid I want to define another TextBox style but inherit from the one defined in DataGrid style.
Is there a way to make a style inherit from the style that is currently defined for a specific control in the current 'context'?
EDIT:
To make it more clear, here's what I have:
<!-- explicit style for all TextBoxes -->
<Style TargetType="{x:Type TextBox}" x:Key="TextStyle">
<Setter Property="FontSize" Value="16"/>
</Style>
<!-- implicit style for all TextBoxes -->
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource TextStyle}"/>
<!-- DataGrid style changing inner TextBox style -->
<Style TargetType="{x:Type DataGrid}">
<Style.Resources>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource TextStyle}">
<Setter Property="FontSize" Value="20"/>
</Style>
<!-- since TextBox has defined implicit style this would be equivalent to -->
<!--<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="FontSize" Value="20"/>
</Style>-->
</Style.Resources>
</Style>
<Control>
<DataGrid>
<Row>
<TextBox/> <!-- should show as defined in DataGrid style -->
</Row>
<Row>
<Row.Resources>
<Style TargetType="{x:Type TextBox}" BasedOn=" ??? ">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
</Row.Resources>
<TextBox/> <!-- should show with additional trigger -->
</Row>
</DataGrid>
</Control>
What to put in BasedOn = '???' so that the text shows up in FontSize 20 but Bold if hovered.
You cannot add two Styles with the same key inside the same ResourceDictionary. So if you already have defined an implicit Style without an x:Key in a ResourceDictionary for a specific type, you cannot add another one to the same ResourceDictionary.
Otherwise you should be able to base a Style on the default style that is in scope like this:
<Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
<Style.Triggers>
</Style.Triggers>
</Style>
Please use the following for the textbox inside the datagrid:
<Style TargetType="TextBox" BasedOn="{StaticResource <your style name>}">
PS: would be TextBoxStyleBase in your case.

inherit style from default style

In my project there is a custom style for text box. It is defined as:
<Style TargetType="TextBox"/>
So it is applied to all text box child controls by default.
I need to create another style that is based on default style. But how do I specify in the BasedOn attribute that my new style should use the default style?
Use the type of the control you would like to extend
BasedOn="{StaticResource {x:Type TextBox}}"
Full example:
<Style x:Key="NamedStyle" TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter property="Opacity" value="0.5" />
</Style>
#Aphelion has the correct answer. I would like to add that the order in which items are defined in the ResourceDictionary matter.
If you override the default style of a slider and you want to base another slider style on that, you must declare the "based on" slider after the override style.
For example, if you do this:
<Style x:Key="BlueSlider" TargetType="{x:Type Slider}" BasedOn="{StaticResource {x:Type Slider}}">
<Setter Property="Background" Value="Blue"/>
</Style>
<Style TargetType="{x:Type Slider}">
<Setter Property="Foreground" Value="Yellow"/>
</Style>
BlueSlider will have a blue background with the default (white) foreground.
But if you do this:
<Style TargetType="{x:Type Slider}">
<Setter Property="Foreground" Value="Yellow"/>
</Style>
<Style x:Key="BlueSlider" TargetType="{x:Type Slider}" BasedOn="{StaticResource {x:Type Slider}}">
<Setter Property="Background" Value="Blue"/>
</Style>
BlueSlider will have a blue background and a yellow foreground.

Putting Styles on controls inside a Grid style

I want' to define that every control of specific type inisde a grid gets a Style. This is easy just put the styles with TargetType inside the grid resources. But what then if I wan't to reuse this grid as a style?
I can create a grid style and have a setter to resources but can only put one style there.
<Style x:Key="GridStyle" TargetType="Grid">
<Setter Property="Resources">
<Setter.Value>
<Style TargetType="TextBlock" BasedOn="{StaticResource MainText}" />
<Style TargetType="{x:Type RowDefinition}">
<Setter Property="Height" Value="Auto"/>
</Style>
<Style TargetType="Button" BasedOn="{StaticResource MainButton}" />
</Setter.Value>
</Setter>
</Style>
Won't work because the setter can only put one style in.
This is probably something very simple but I'm not getting it and I don't wan't to repeat these styles in each and every grid.
If you put the Styles inside the Resources of the outer style, they will be in scope inside the grids:
<Style x:Key="GridStyle" TargetType="Grid">
<Style.Resources>
<Style TargetType="TextBlock" BasedOn="{StaticResource MainText}" />
<Style TargetType="{x:Type RowDefinition}">
<Setter Property="Height" Value="Auto"/>
</Style>
<Style TargetType="Button" BasedOn="{StaticResource MainButton}" />
</Style.Resources>
</Style>

Resources