WPF StaticResource for width - wpf

<Style x:Key="Small" TargetType="Button">
<Setter Property="Width" Value="80"/>
</Style>
<Style x:Key="DefaultButtonStyleSmall" TargetType="Button" BasedOn="{StaticResource ButtonBaseStyle}">
<Setter Property="Width" Value="{StaticResource Small}" />
</Style>
I get the error
System.Window.Style is not a valid value for the System.Windows.FrameworkElement.Width property on a setter
What am I doing wrong?

You are assigning a Style to a property, not to the control that has that property. Since you apparently want to use the value in a Style, it can't be a Style itself - it has to be of the same type as the target property, i.e. a Double:
Define the system namespace
xmlns:system="clr-namespace:System;assembly=mscorlib"
And define Small as a Double, not a Style:
<system:Double x:Key="Small">80</system:Double>
Also, keep in mind that this will only work if the button doesn't have a Width set because local values (e.g. Width="Auto") take precedence over style values.

Related

Bind to default property value of another control style definition in xaml

I have a CustomControl and want to have the default value of TextBox default style definition. I don't know if it that is even possible.
This is what I have tried so far without success. But here you can see what I have in mind.
My default implementation to change the default style of the TextBox (in for example app.xaml to apply it global)
<Style TargetType="TextBox">
<Setter Property="BorderThickness" Value="2"/>
</Style>
Here I want to get the value of '2'.
<Style TargetType="controls:CustomControl">
<Setter Property="BorderThickness" Value="{Binding Source={x:Static TextBox.BorderThicknessProperty}}"/>
</Style>
The default value of the BorderThickness property of a TextBox is defined in the default style of the TextBox which is eventually applied to an instance of a TextBox at runtime.
So you cannot do something like this:
<Style TargetType="controls:CustomControl">
<Setter Property="BorderThickness" Value="{Binding Source={x:Static TextBox.BorderThicknessProperty}}"/>
</Style>
...unless you bind to an actual instance of a TextBox that uses the default style.
You could look at the default template of the TextBox and simply copy its default BorderThickness property value of 1 though:
<Style TargetType="controls:CustomControl">
<Setter Property="BorderThickness" Value="1"/>
</Style>
Obviously you can also bind to a property of a class from more than one Style, e.g.:
<Style TargetType="controls:CustomControl">
<Setter Property="BorderThickness" Value="{Binding Thickness, Source={StaticResource settings}}"/>
</Style>

Cannot base style on another style

I have some locally defined styles within Window.Resources. I have some styles for a TextBlock, TextBox, CheckBox and RadioButton. These are supposed to be applied to all controls in the window, so I haven't provided a value for x:Key. I would like them to inherit from a style targeting FrameworkElement. So I have something like:
<Style TargetType="{x:Type RadioButton}">
...
</Style>
<Style TargetType="{x:Type TextBlock}">
...
</Style>
<Style TargetType="{x:Type TextBox}">
...
</Style>
<Style TargetType="{x:Type CheckBox}">
...
</Style>
<Style x:Key="TriggerBase" TargetType="{x:Type FrameworkElement}">
<Style.Triggers>
<Trigger Property="UIElement.IsMouseOver" Value="True">
...
</Trigger>
</Style.Triggers>
</Style>
My problem is that I am unable to set the BasedOn property to inherit from my TriggerBase style. After looking at similar questions, such as this and this, I still cannot get it working. These answers suggest you need to specify the TargetType on your base style, which I have done.
I thought maybe the Styles have to target the exact same type, but after digging around on MSDN I found that wasn't the problem:
If you create a style with a TargetType property and base it on another style that also defines a TargetType property, the target type of the derived style must be the same as or be derived from the type of the base style.
If I set BasedOn like BasedOn="{DynamicResource TriggerBase}", it can find my TriggerBase, but I get an error stating:
A 'DynamicResourceExtension' cannot be set on the 'BasedOn' property
of type 'Style'. A 'DynamicResourceExtension' can only be set on a
DependencyProperty of a DependencyObject.
If I try BasedOn="{StaticResource TriggerBase}", I get an error that it cannot find TriggerBase. One of the linked answers above showed using StaticResource like BasedOn="{StaticResource {x:Type FrameworkElement}, but it still cannot resolve the style.
How can I inherit from the TriggerBase style? I'm targeting .NET 4.5.
You are correct and you can base your styles on FrameworkElement style just need to move
<Style x:Key="TriggerBase" TargetType="{x:Type FrameworkElement}">
</Style>
to the top and then
<Style TargetType="{x:Type RadioButton}" BasedOn="{StaticResource TriggerBase}">
will work

WPF Styling all elements using UIElement

Here's something I want to do:
<Application.Resources>
<Style TargetType="{x:Type UIElement}">
<Setter Property="Opacity"
Value=".1" />
</Style>
</Application.Resources>
So that I can style any type (not just some final concrete UI type). I am not looking for best practices, its more of a question to ponder.
I noticed that WPF does not style any super class specified in TargetType (UIElement, FrameworkElement, etc etc). It styles only if the TargetType equates to the concrete UI class (Button, Rectangle).
if you just want to define a base Style, you can however use BasedOn property.
<Style TargetType="FrameworkElement" x:Key="ElementBase">
<Setter Property="Height" Value="24"/>
</Style>
<Style TargetType="TextBlock" BasedOn="{StaticResource ElementBase}">
</Style>
It is a little bit more work, but maybe it helps.

WPF Replacing AND extending styles

How do I change what WPF's idea of the default style for a control is? And why is this happening in the first place? In the below XAML, I declare a Style for Button, and then further declare a new Style that overrides one of the setters called "HugeBut". I would expect that HugeBut is implicitly BasedOn my new un-named style, but apparently it is not;
<Window.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="Red">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- badness -->
<Style TargetType="{x:Type Button}" x:Key="HugeBut">
<Setter Property="Foreground" Value="Yellow"/>
</Style>
<!-- works, but I do not want to explicitly set the based-on. -->
<Style TargetType="{x:Type Button}" x:Key="HugeBut" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Foreground" Value="Yellow"/>
</Style>
</Window.Resources>
<Button Content="Regular" />
<Button Content="huge!" Style="{StaticResource HugeBut}"/>
You would expect two red buttons, one with black text and one with yellow, but Style HugeBut inherits all of the values that I did not specify in my unnamed style from the system default theme for Button (Aero in my case).
What can I do to change this behavior?
It appears that the answer is here:
http://wpfthemereplacer.codeplex.com/
From the site description:
This library allows users to provide their own resource dictionaries
to replace the default theme dictionaries loaded by WPF. This makes it
so you don't have to decorate custom styles with
BasedOn="{StaticResource {x:Type ...}}" when your own custom theme is
being used in your application. It also makes it so if you have custom
controls that just provide enhanced capability and don't need to
replace the the style, you don't need to define a new style or
override the DefaultStyleKey when you create the custom control.
This is exactly what I'm looking for. This will allow me to use Styles as they are meant to be used across an app that has been extensively "re-themed", rather than theme-ing by setting global styles (and then deal with tracking down bits of code that are missing BasedOn, or cannot deal with it at all due to WPF bugs and other constraints)
works, but I do not want to explicitly set the based-on.
Well, the framework does not really care if you don't want to, for all i know, you have to.

WPF global font size

I'm creating a WPF app and I would like to know the best way to be able to change the font size for every element in the ui. Do I create a resource dictionary and set Styles to set the font size for all the controls I use?
What is the best practice?
I'd do it this way:
<Window.Resources>
<Style TargetType="{x:Type Control}" x:Key="baseStyle">
<Setter Property="FontSize" Value="100" />
</Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource baseStyle}"></Style>
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource baseStyle}"></Style>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource baseStyle}"></Style>
<Style TargetType="{x:Type ListView}" BasedOn="{StaticResource baseStyle}"></Style>
<!-- ComboBox, RadioButton, CheckBox, etc... -->
</Window.Resources>
That way, if I want to change ALL the controls, I'd just have to change the "baseStyle" style, the rest would just inherit from it. (That's what BasedOn property those, you can also extend the base style if you create other setters inside of the inherited style)
FontSizeProperty is inherited from Parent Control. So you just need to change FontSize of your main window.
If you don't need dynamic behaviour this should work:
Add a style for Window to your ResourceDictionary
<Style TargetType="{x:Type Window}">
<Setter Property="FontSize" Value="15" />
</Style>
Apply the style to your main form (will not be applied implicit because its a derived type)
Style = (Style)FindResource(typeof (Window));
<Window> has a property FontSize.
So you can set desired fontsize in element if you want to change the fontsize in all the elements within that window.
<Window FontSize="12">
</Window>
Another option is to define the FontFamily and FontSize as resources.
<FontFamily x:Key="BaseFontFamily">Calibri</FontFamily>
<sys:Double x:Key="BaseFontSize">12</sys:Double>
That way you can use them in your setters.
Application.Current.MainWindow.FontSize = _appBodyFontSize;
This way you can change the Font Size at run time also.
TextElement.FontSize is an inherit property, which means you can simply set the font size at root element, and all the children elements will use that size (as long as you don't change them manually)
For any styles in WPF, you should have a separate resource dictionary that contains the styles for your app.
If you want to have a single Font Size that's reused throughout the app then just create a style for that font size. You can either give it a unique name/key to use explicitly or you can set a targetType that will transcend throughout the app.
Explicit Key:
<Style
x:Key="MyFontSize"
TargetType="TextBlock">
<Setter
Property="FontSize"
Value="10" />
</Style>
<Control
Style="{StaticResource MyFontSize}" />
*Note this style can be used with controls that have contentPresenters
For all textblocks in the app:
<Style
TargetType="TextBlock">
<Setter
Property="FontSize"
Value="10" />
</Style>
<TextBlock
Text="This text will be size 10" />
If you need to programmatically change global FontSize, not statically (XAML), to be applied once for all your windows, you can do:
TextElement.FontSizeProperty.OverrideMetadata(
typeof(TextElement),
new FrameworkPropertyMetadata(16.0));
TextBlock.FontSizeProperty.OverrideMetadata(
typeof(TextBlock),
new FrameworkPropertyMetadata(16.0));
This values are applied to any TextBlock, Labels and almost any text in any windows, whereas it has not a explicit FontSize defined. But this does not affect for TextBox, you have to write a similar code for it or any other special controls.
To dynamically change the font size globally with ctrl-mousewheel:
XAML:
<Window Name="MainWindow" ... PreviewMouseWheel="MainWindow_PreviewMouseWheel">
code behind:
private void MainWindow_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if ((Keyboard.Modifiers & ModifierKeys.Control) != 0)
{
if (e.Delta > 0)
++mainCtrl.FontSize;
if (e.Delta < 0 && mainCtrl.FontSize > 1)
--mainCtrl.FontSize;
}
}
Using Resources in XAML is the way to go. Although there are many great answers to this question, I would like to add my two cents to the SCOPE of the Resource.
For Global accessibility in all of the Windows and User Controls of the Project, you can have your resource in the App.xaml file
<Application.Resources>
<Style TargetType="{x:Type Control}" x:Key="GlobalFontSize">
<Setter Property="FontSize" Value="28"/>
</Style>
</Application.Resources>
For accessibility at a Window level, you can have your resource in your xaml file for Window
<Window.Resources>
<Style TargetType="{x:Type Control}" x:Key="GlobalFontSize">
<Setter Property="FontSize" Value="28"/>
</Style>
</Window.Resources>
You could even have it at a Control level, for example
<DockPanel.Resources>
<Style TargetType="{x:Type Control}" x:Key="GlobalFontSize">
<Setter Property="FontSize" Value="28"/>
</Style>
</DockPanel.Resources>
Let's have some BLACK MAGIC things:
Add a double resource into your Application resource
<Application.Resources>
<sys:Double xmlns:sys="clr-namespace:System;assembly=mscorlib" x:Key="GlobalFontSize">12</sys:Double>
</Application.Resources>
Add a static property in your App class
public static double GlobalFontSize
{
get => (double)Current.Resources["GlobalFontSize"];
set => Current.Resources["GlobalFontSize"] = value;
}
Use this resource any where you want by DynamicResource
FontSize="{DynamicResource GlobalFontSize}"
Access property App.GlobalFontSize in any way to change value, binding is okay!
App.GlobalFontSize = 20;
//Or
{Binding Path=(local:App.GlobalFontSize)}

Resources