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.
Related
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>
How can I extend upon the style I have declared in CustomTreeView? so that I have a lightgray foreground and a green background?
CustomTreeView.xaml
<TreeView x:Class="WpfApplication17.CustomTreeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="Foreground" Value="LightGray"/>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
Window.xaml
<Window x:Class="WpfApplication17.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication17">
<local:CustomTreeView ItemsSource="{Binding Data}">
<local:CustomTreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}">
<Setter Property="Background" Value="Green"/>
</Style>
</local:CustomTreeView.ItemContainerStyle>
</local:CustomTreeView>
</Window>
Not sure if this is the right approach, but I ended up using it.
<TreeView x:Class="WpfApplication17.CustomTreeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TreeView.Resources>
<Style x:Key="m_itemContainerStyle" TargetType="{x:Type TreeViewItem}">
<Setter Property="Foreground" Value="LightGray"/>
</Style>
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style BasedOn="{StaticResource m_itemContainerStyle}" TargetType="{x:Type TreeViewItem}">
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
<Window x:Class="WpfApplication17.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication17">
<local:CustomTreeView ItemsSource="{Binding Data}">
<local:CustomTreeView.ItemContainerStyle>
<Style BasedOn="{StaticResource m_itemContainerStyle}" TargetType="{x:Type TreeViewItem}">
<Setter Property="Background" Value="Green"/>
</Style>
</local:CustomTreeView.ItemContainerStyle>
</local:CustomTreeView>
</Window>
It's not uncommon for me to write something like below for styling a data entry form, but my problem is that TextBox and TextBlock don't seem to implement the Setters that are in the BaseElementStyle. Usually I need to define them separately.
Why is this? And is there a way around it?
I am guessing it has to do with the fact they are usually used in other control templates (for example TextBlock is used in most controls and TextBox is used in DatePickers and ComboBoxes)
<Style x:Key="BaseElementStyle" TargetType="{x:Type FrameworkElement}">
<Setter Property="Margin" Value="5" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type DatePicker}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource BaseElementStyle}" />
I would like to suggest the two possible workarounds. It seems that each of Key and Type can be used but both of them cannot be used together as your question case, x:Key="BaseElementStyle" TargetType="{x:Type FrameworkElement}".
using x:Key
<Style x:Key="BaseElementStyle">
<Setter Property="FrameworkElement.Margin" Value="5" />
<Setter Property="FrameworkElement.VerticalAlignment" Value="Center" />
</Style>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type DatePicker}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource BaseElementStyle}" />
using x:Type
<Style TargetType="{x:Type FrameworkElement}">
<Setter Property="Margin" Value="5" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type FrameworkElement}}" />
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type FrameworkElement}}" />
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource {x:Type FrameworkElement}}" />
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource {x:Type FrameworkElement}}" />
<Style TargetType="{x:Type DatePicker}" BasedOn="{StaticResource {x:Type FrameworkElement}}" />
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource {x:Type FrameworkElement}}" />
Also keep in mind that WPF considers a ControlTemplate to be an inflation boundary and does NOT apply default styles inside of templates. The exception to the rule: anything that inherits from Control WILL BE inflated with the default style. Since TextBlock inherits from FrameworkElement and not from Control, if you use of it inside of a ControlTemplate you will also have to apply it's style manually. This is true for both TextBlocks that are added by hand, or by TextBlocks added by WPF for string Content. A quick example:
<Window x:Class="ImplicitStyles.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<StackPanel.Resources>
<Style x:Key="BaseElementStyle">
<Setter Property="FrameworkElement.Tag" Value="Hello World" />
</Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource BaseElementStyle}" />
<!-- Default style for TextBlock will not be applied, Tag will be null -->
<ControlTemplate x:Key="MyContentControlTemplateOne" TargetType="{x:Type ContentControl}">
<Border BorderBrush="Red" BorderThickness="2">
<TextBlock Text="{Binding RelativeSource={RelativeSource Self}, Path=Tag}" />
</Border>
</ControlTemplate>
<!-- Default style for Button will be applied, Tag will be Hello World -->
<ControlTemplate x:Key="MyContentControlTemplateTwo" TargetType="{x:Type ContentControl}">
<Border BorderBrush="Red" BorderThickness="2">
<Button Content="{Binding RelativeSource={RelativeSource Self}, Path=Tag}" />
</Border>
</ControlTemplate>
</StackPanel.Resources>
<ContentControl Template="{StaticResource MyContentControlTemplateOne}" />
<ContentControl Template="{StaticResource MyContentControlTemplateTwo}" />
</StackPanel>
</Window>
For more information, see this blog post:
http://blogs.msdn.com/b/wpfsdk/archive/2009/08/27/implicit-styles-templates-controls-and-frameworkelements.aspx
Well i have my file Styles.xaml thats merged in the Application.xaml so it applies to every thing..
here are my styles
<Style TargetType="{x:Type Control}" x:Key="baseStyle">
<Setter Property="FontFamily" Value="Verdana"/>
<Setter Property="FontSize" Value="12"/>
</Style>
<Style TargetType="Button" BasedOn="{StaticResource baseStyle}">
<Setter Property="Margin" Value="2,0,2,0"/>
<Setter Property="Padding" Value="2"/>
<Setter Property="FontSize" Value="50"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="FontFamily" Value="Verdana"/>
<Setter Property="FontSize" Value="12"/>
</Style>
When im in the editor this seems to work but when i run the application the font-size of the buttons are shrinked to their normal sizes..
My guess is that the buttons create a TextBlock when their content is set to a string and then use the textblock style.. but how can i override this?
You're right about
My guess is that the buttons create a
TextBlock when their content is set to
a string and then use the textblock
style
. See this post.
A workaround is to define a
DataTemplate for System.String, where
we can explicitly use a default
TextBlock to display the content. You
can place that DataTemplate in the
same dictionary you define the
TextBlock style so that this
DataTemplate will be applied to
whatever ContentPresenter effected by
your style.
So adding the DataTemplate at the end to Styles.xaml will fix the problem
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Style TargetType="{x:Type Control}" x:Key="baseStyle">
<Setter Property="FontFamily" Value="Verdana"/>
<Setter Property="FontSize" Value="12"/>
</Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource baseStyle}">
<Setter Property="Margin" Value="2,0,2,0"/>
<Setter Property="Padding" Value="2"/>
<Setter Property="Foreground" Value="Red" />
<Setter Property="FontSize" Value="50"/>
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontFamily" Value="Verdana"/>
<Setter Property="Foreground" Value="Green" />
<Setter Property="FontSize" Value="24"/>
</Style>
<DataTemplate DataType="{x:Type sys:String}">
<TextBlock Text="{Binding}">
<TextBlock.Resources>
<Style TargetType="{x:Type TextBlock}"/>
</TextBlock.Resources>
</TextBlock>
</DataTemplate>
</ResourceDictionary>
This will keep your Style for a TextBlock but the TextBlock created in a Button for example won't be effected by it
I tried your styles, and it works well. So your styles are not the problem. I think it's the place you merged the style as you wrote. You'd better put your ResourceDictionary Styles.xaml in your MainWindow file instead of your Application.xaml.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<TextBlock>TTT</TextBlock>
<Button>BBB</Button>
</StackPanel>
</Window>
But your problem remains unclear, if it's not the solution could you clarify a bit more the way you use your styles by posting this part of your code?
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}"/>