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

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>

Related

XAML Style Trigger - Change Style ONLY for Object of with a specific Name

I am new XAML however I am given the task to override some styles for certain elements within an existing application.
In my custom Theme, I am attempting to override the style of a BORDER control.
From what I can tell (using Snoop) to inspect the application, the element I want to change is just a plain border.
The border also seems to have a Name of "SubMenuBorder". Please see the image below.
Here is the latest iteration of my style snippet in which I am trying to set the border control's Background, BorderBrush and BorderThickness BUT ONLY if the control has a name of "SubMenuBorder"
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<Trigger Property="Name" Value="SubMenuBorder">
<Setter Property="Background" Value="Red"></Setter>
<Setter Property="BorderBrush" Value="Red"></Setter>
<Setter Property="BorderThickness" Value="20"></Setter>
</Trigger>
</Style.Triggers>
</Style>
Unfortunately the above does NOT work.
The style trigger does not seem to fire/apply to the intended control.
If I simplify things further and just style ALL borders with the following snippet, then it seems to work and the border control I want to change, is styled, but so is every other border control in the application.
<Style TargetType="{x:Type Border}">
<Setter Property="Background" Value="Red"></Setter>
<Setter Property="BorderBrush" Value="Red"></Setter>
<Setter Property="BorderThickness" Value="20"></Setter>
</Style>
Further Findings
I attempted to use a DataTrigger... which unfortunately doesn't work either.
Snoop shows below that the data trigger is being satisfied, however on the second image below you can see that the property of the background and borderbrush are still from the parenttemplate.
Any ideas please?
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Name}" Value="SubMenuBorder">
<Setter Property="Background" Value="Red"></Setter>
<Setter Property="BorderBrush" Value="Red"></Setter>
<Setter Property="BorderThickness" Value="20"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
You cannot use triggers to modify a Border that is defined in a ControlTemplate, with the exception of using an implicit Style that applies to all elements of the type specified by the TargetType property of the implicit Style.
You will either have to modify the ControlTemplate itself, or programmatically find the Border element in the visual tree and then change its runtime property values. The first approach, i.e. modifying or creating a custom template, is the recommended approach.
The name "SubMenuBorder" is only known and applicable within that Border element's namescope.

MahApps.Metro change ToggleSwitch style

I'm testing wpf applications using MahApp.Metro.
Somehow I'm not able to change the style of the ToggleSwitch. I just want to change simple properties like foreground or background of the switch. What am I doing wrong?
Mainwindow.xaml
<Style x:Key="flyoutToggleSwitchStyle" TargetType="{x:Type Controls:ToggleSwitch}" BasedOn="{StaticResource {x:Type Controls:ToggleSwitch}}">
<Setter Property="BorderBrush" Value="WhiteSmoke"/>
<Setter Property="Background" Value="White"/>
<Setter Property="Foreground" Value="Yellow"/>
<Setter Property="OnLabel" Value="Yes"/> <!--<<<---THIS WORKS!!-->
<Setter Property="OffLabel" Value="No"/>
</Style>
<Controls:ToggleSwitch Style="{StaticResource flyoutToggleSwitchStyle}">
<Controls:ToggleSwitch.Header>
<TextBlock>
Test
</TextBlock>
</Controls:ToggleSwitch.Header>
</Controls:ToggleSwitch>
Now there is a new ToggleSwitch property called SwitchForeground which allows changing the colour for ON position (tested on v0.14).
Example:
<controls:ToggleSwitch SwitchForeground="{StaticResource MyGreen}" />
The problem is that in the Mahapps.Metro ToggleSwitch most of the properties can not be changed within a style, because there is no TemplateBinding or Key defined in the original template definition.
So the style can only be changed by creating a new template. For this the ToggleSwitch and the ToggleSwitchButton templates have to be changed.
Issue on GitHub
Source of the templates

WPF DataGrid*Column: set EditingElementStyle

I'm trying to modify the default style of DataGrid*Column. But it seems that the style is not used by DataGrid.
<Style x:Key="DataGridTextColumn_EditStyle" TargetType="{x:Type TextBox}" >
<Setter Property="SelectionBrush" Value="Red" />
</Style>
<Style TargetType="{x:Type DataGridTextColumn}">
<Setter Property="EditingElementStyle" Value="{StaticResource DataGridTextColumn_EditStyle}" />
</Style>
This way it shouldn't be necessary to set the style in DataGrid.Columns.
It's not possible to define default Style for DataGridTextColumn because DataGridTextColumn class is not FrameworkElement so it doesn't have Style property.

Specify a binding in an application-level style resource?

I'm fairly new to WPF and have created a style to alter the appearance of a button control. The style contains a data trigger to change the button background (amongst other things) based on a boolean property in the data context, e.g.:-
<Style x:Key="IndicatorButton" TargetType="Button">
<DataTrigger Binding="{Binding Path=ValveIsOpen}" Value="True">
<Setter Property="Background" Value="#00FF00"/>
..etc..
Currently the style is only used by a single button, so the data trigger binding is hard-coded with a property called "ValveIsOpen".
I now want to re-use this style throughout my app, with different buttons being bound to different properties. How would I change the data trigger binding on each button that the style is applied to?
Many thanks
You need to define a base style and derived styles, such as
<Style x:Key="IndicatorButton" TargetType="Button">
<Setter Property="Foreground" .../>
...
<Style x:Key="ValveIndicatorButton" TargetType="Button" BasedOn={StaticResource IndicatorButton}>
<DataTrigger Binding="{Binding Path=ValveIsOpen}" Value="True">
<Setter Property="Background" Value="#00FF00"/>
..etc..

Can you define multiple TargetTypes for one XAML style?

In HTML/CSS you can define a style which can be applied to many types of elements, e.g.:
.highlight {
color:red;
}
can be applied to both P and DIV, e.g.:
<p class="highlight">this will be highlighted</p>
<div class="highlight">this will also be highlighted</div>
but in XAML you seem to have to define the TargetType for styles, otherwise you get an error:
<Style x:Key="formRowLabel" TargetType="TextBlock">
is there a way to allow a XAML style to be applied to multiple elements or even to leave it open as in CSS?
The setters in WPF styles are checked during compile time; CSS styles are applied dynamically.
You have to specify a type so that WPF can resolve the properties in the setters to the dependency properties of that type.
You can set the target type to base classes that contain the properties you want and then apply that style to derived classes. For example, you could create a style for Control objects and then apply it to multiple types of controls (Button, TextBox, CheckBox, etc)
<Style x:Key="Highlight" TargetType="{x:Type Control}">
<Setter Property="Foreground" Value="Red"/>
</Style>
...
<Button Style="{StaticResource Highlight}" Content="Test"/>
<TextBox Style="{StaticResource Highlight}" Text="Test"/>
<CheckBox Style="{StaticResource Highlight}" Content="Test"/>
<!-- Header text style -->
<Style x:Key="headerTextStyle">
<Setter Property="Label.VerticalAlignment" Value="Center"></Setter>
<Setter Property="Label.FontFamily" Value="Trebuchet MS"></Setter>
<Setter Property="Label.FontWeight" Value="Bold"></Setter>
<Setter Property="Label.FontSize" Value="18"></Setter>
<Setter Property="Label.Foreground" Value="#0066cc"></Setter>
</Style>
<!-- Label style -->
<Style x:Key="labelStyle" TargetType="{x:Type Label}">
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Margin" Value="0,0,0,5" />
</Style>
I think both of these methods of declaring a style might answer your question.
In the first one, there is no TargetType specified, but the property names are prefixed with 'Label'. In the second one, the style is created for Label objects.
Another method to do it is:
<UserControl.Resources>
<Style x:Key="commonStyle" TargetType="Control">
<Setter Property="FontSize" Value="24"/>
</Style>
<Style BasedOn="{StaticResource commonStyle}" TargetType="ListBox"/>
<Style BasedOn="{StaticResource commonStyle}" TargetType="ComboBox"/>
</UserControl.Resources>
I wanted to apply a style to a Textblock and a TextBox but the selected answer didn't work for me because Textblock doesn't inherit from Control, in my case I wanted to affect the Visibility property, so I used FrameworkElement
<Style x:Key="ShowIfRequiredStyle" TargetType="{x:Type FrameworkElement}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ShowIfRequiredStyle, UpdateSourceTrigger=PropertyChanged}" Value="true">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
<TextBlock Style="{StaticResource ResourceKey=ShowIfRequiredStyle}"/>
<TextBox Style="{StaticResource ResourceKey=ShowIfRequiredStyle}"/>
This works for the Visibility property because both items inherit from Frameworkelement and the property is defined there. Of course this will not work for properties defined only in Control, you can search the hierarchy tree and try to find a base class, anyway I thought this could help someone since this is a top search result and the selected answer is a little incomplete.
There is an alternative answer to the question. You CAN leave the TargetType parameter off the style altogether which will allow it to apply to various different controls, but only if you prefix the property name with "Control."
<Style x:Key="Highlight">
<Setter Property="Control.Foreground" Value="Red"/>
</Style>
Obviously, this only works for properties of the base control class. If you tried to set ItemsSource say, it would fail because there is no Control.ItemsSource
I got this working
<Style x:Key="HeaderStyleThin" TargetType="{x:Type Border}">
<Setter Property="Background" Value="Black" />
<Style.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background=" Value="Red" />
</Style>
</Style.Resources>
</Style>

Resources