Implicit Styles not working on Custom Controls - wpf

In my App.xaml I have a few implicit styles
<Style TargetType="{x:Type Button}">
...Blah...
</Style>
These styles work for control as long as they are not in a custom control I create.
My Control
public class NavigationControl : Control
{
public static readonly DependencyProperty ButtonStyleProperty =
DependencyProperty.Register("ButtonStyle", typeof(Style), typeof(NavigationControl));
public Style ButtonStyle
{
get { return (Style)GetValue(ButtonStyleProperty); }
set { SetValue(ButtonStyleProperty, value); }
}
}
static NavigationControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(NavigationControl), new FrameworkPropertyMetadata(typeof(NavigationControl)));
}
public NavigationControl()
{
}
My Control Styles and Templates
<ControlTemplate x:Key="NavigationControlTemplate" TargetType="{x:Type controls:NavigationControl}">
<Button Style="{TemplateBinding ButtonStyle}"
</ControlTemplate>
<Style x:Key="DefaultButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="MinWidth" Value="75"/>
<Setter Property="Height" Value="50"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Margin" Value="-1"/>
</Style>
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource DefaultButtonStyle}">
<Setter Property="Template" Value="{StaticResource NavigationButtonTemplate}"/>
</Style>
<Style TargetType="{x:Type controls:NavigationControl}">
<Setter Property="Template" Value="{StaticResource NavigationControlTemplate}"/>
<Setter Property="ButtonStyle" Value="{StaticResource ButtonStyle}"/>
</Style>
Now I would assume that the DefaultButtonStyle's BasedOn would get it from the App level. But it doesnt. The only way to apply the app level style is Override the ButtonStyle by creating a style of type NavigationControl.
Is there a way where the implicit style makes this work?

Setting BasedOn="{StaticResource {x:Type Button}}" will get you WPF's default button style. If you want to use the style defined in your App.xaml, you'll need to add a key to that style so you could reference it from your control style:
App.xaml
<!-- Your style, just with an added x:Key -->
<Style x:Key="myButtonStyle" TargetType="{x:Type Button}">
...
</Style>
<!-- Set the above style as a default style for all buttons -->
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource myButtonStyle}">
Your control styles and templates
<Style x:Key="DefaultButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource myButtonStyle}">
...
</Style>

Related

Why is styles not getting applied to ToggleButton?

<Window.Resources>
<vm:NotesViewModel x:Key="vm"/>
<Style TargetType="ToggleButton">
<Setter Property="Height" Value="50"/>
<Setter Property="Width" Value="50"/>
</Style>
</Window.Resources>
But the ToggleButton in toolbars size remains unchanged. If set the size right there with defintion, it changes but not through window styles in resources.
What am I missing?
The ToolBar applies its own ToggleButton style which you can override by defining a style with an x:Key of ToolBar.ToggleButtonStyleKey:
<Style TargetType="ToggleButton">
<Setter Property="Height" Value="50"/>
<Setter Property="Width" Value="50"/>
</Style>
<Style x:Key="{x:Static ToolBar.ToggleButtonStyleKey}"
TargetType="ToggleButton" BasedOn="{StaticResource {x:Type ToggleButton}}"/>

Binding to MainWindowViewModel property from app.xaml

I am trying to change the font-size globally. For this, I added styles in app.xaml. Here my FontSz property is in MainWindowViewModel. Is there any way to make this binding possible?
<Application.Resources>
<Style TargetType="{x:Type Control}" x:Key="baseStyle">
<Setter Property="FontSize" Value="{Binding Path=???.FontSz}" />
</Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource baseStyle}"/>
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource baseStyle}"/>
</Application.Resources>
You will need to use DynamicResouce for this. Add the system namespace as below
xmlns:system="clr-namespace:System;assembly=mscorlib"
<Application.Resources>
<system:Double x:Key="FontSz">20</system:Double>
<Style x:Key="baseStyle"
TargetType="{x:Type Control}">
<Setter Property="FontSize"
Value="{DynamicResource FontSz}"/>
</Style>
<Style TargetType="{x:Type Button}"
BasedOn="{StaticResource baseStyle}"/>
<Style TargetType="{x:Type Label}"
BasedOn="{StaticResource baseStyle}"/>
</Application.Resources>
MainWindowViewModel
In your command execution, add the following code:
Application.Current.Resources["FontSz"] = 18d;
You can change the fontsize from 18d to the fontsize selected by the user in your MainViewModel.

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.

How to target all controls (WPF Styles)

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}"/>

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