How to apply styles to user control? - wpf

<StackPanel>
<local:SpoilerControl x:Name="spoiler" Other="true">
<UserControl.Style>
<Style TargetType="UserControl">
<Setter Property="Secret" Value="New secret value"/>
</Style>
</UserControl.Style>
</local:SpoilerControl>
</StackPanel>
I have a user control which was property Secret which is just string value. How can I set that in styles? I think I need to set something else in TargetType? Because it doesn't build (can't find the property).
error MC4005: Cannot find the Style Property 'Secret' on the type
'System.Windows.Controls.UserControl'

Assuming you have defined Secret as a dependency property, TargetType="{x:Type local:SpoilerControl}" should work

Related

css !Important in WPF style

I have text block with MaxWidth="80" and want change on Style without remove MaxWidth="80"
the TextBlock is at third party control
for sample:
<Window.Resources>
<Style TargetType="TextBox" >
<Setter Property="Foreground" Value="Red" />
<Setter Property="FontSize" Value="10"/>
</Style>
</Window.Resources>
<Grid>
<TextBox FontSize="45" Foreground="Blue" Text="OH My God"/>
</Grid>
Not sure i'm answering what you asked, since, as other users pointed out, the question is not well written. But...
A setter within a style has less priority than setting the property directly on the instance of the object.
So, even though your style declares
<Setter Property="MaxWidth" Value="80"/>
If you write your textblock/textbox like this
<TextBlock MaxWidth="100"/>
the 100 will prevail on the 80, thus the max width will be 100.
In the WPF there is a strict rule which property is about to be used.
So you can:
Define a default style with the property = 100.
Define another style based on the default and override the property as you wish.
Apply the new created style to your TextBox.
And attribute has more power than a style.

Control template and theme-related data separation through the Resource Dictionaries

I have several resource dictionaries with theme-related data, where I declared styles for particular element this way:
<Style TargetType="sdk:DataForm">
<Setter Property="Background" Value="{StaticResource Bckgrnd}"/>
</Style>
And also I have Generic.xaml, where I want to set the template for this target type, but I was faced with a situation where in one template I have to use several colors but target type have only one property for color. Something like this:
<Style TargetType="sdk:DataForm">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="sdk:DataForm">
<Grid ctl:DataField.IsFieldGroup="True">
....
<StackPanel Background="{TemplateBinding Background}" ...>
...
...
<!-- and I need another background from themes here -->
<StackPanel Background="{???}" ...>
...
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And the question is: how can I use different colors in this case without something like target type extension? It will be great if you'll find pure xaml solution.
Thanks
I don't know of a pure XAML solution. I think I would create a subclass of DataForm and add dependency properties of type Brush to it. Then use that class in the XAML instead of DataForm, and use TemplateBindings that reference the new properties.
Or, if you don't want to subclass DataForm, perhaps you could create attached properties of type Brush.

Textbox Disabled background from a local trigger without using template

<Window x:Class="AiweeeTest.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">
<Grid>
<Grid.Resources>
<SolidColorBrush x:Key="backcolorType" Color="Red"></SolidColorBrush>
<SolidColorBrush x:Key="forecolorType" Color="Green"></SolidColorBrush>
<Style x:Key="TextboxStyle" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="Yellow"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" Value="{StaticResource backcolorType}"/>
<Setter Property="Foreground" Value="{StaticResource forecolorType}"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<TextBox Name="textbox1" Width="100" Height="25" Style="{StaticResource TextboxStyle}" IsEnabled="False"/>
</Grid>
</Window>
I am not able to update the background of a textbox using the trigger defined above, however when I copy the entire textbox control template template and replace the "DisabledBackgroundBrush" with my own color it does. What's the difference, I've already seen some links over this matter; however I am not able to understand the reason behind it. As I understand, Triggers are fired in the order they are defined, then the trigger defined locally in the window should be able to override the background color of the textbox when disabled. Please clarify.
PS: I am not trying to achieve anything special here, but just want to understand why is this so. This gives me a bit of frustration of WPF not being intuitive for situations like such.
I am guessing it has something to do with the order in which WPF will apply values for a DependencyProperty. This MSDN article has some good information on Dependency Property Precedence
Basically the order goes:
Property system coercion
Active animations, or animations with a Hold behavior.
Local value
TemplatedParent template properties
Triggers from the TemplatedParent template
Property sets (typically through XAML attributes) in the TemplatedParent template
Implicit style
Style triggers
Template triggers
Style setters
Default (theme) style
Active triggers in the theme style
Setters in the theme style
Inheritance
Default value from dependency property metadata

WPF Custom Control TemplateBinding

How do i define a TemplateBinding for my custom control?
a little somthing like this..... (btw, this xaml is WPF, not silverlight--which is slightly different)
<style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Green">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Background={TemplateBinding Background}
</ControlTemplate>
</Setter.Value>
</Setter>
</style>
now, once you apply this style to an object, whenever you set the background of that object, the template will use the Background property (this is a property on the button control) and will be defaulted to what you set in the style (in this case, green)
If you want to use a property that does not exsist on the object of your style, you have to derive your own control and add the property as either a DependencyProperty or use the INotifyPropertyChanged interface. Here is a decent explanation for you.
Need a bit more information on what you are trying to do. Setting up a TemplateBinding can be done with the following XAML:
{TemplateBinding YourProperty}
or
{Binding RelativeSource={RelativeSource TemplatedParent}, Path=YourProperty}

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