WPF unwanted style inheritance - wpf

In my ResourceDictionary I'm setting default style for TextBlock:
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{DynamicResource TextBrush}"/>
<Setter Property="Margin" Value="10" />
</Style>
Then when I put lets say a CheckBox it looks fine in the designer but on runtime the TextBlock inside the CheckBox has that 10 margin.
What can cause that to happen?...
I'm setting the resources inside App.xaml.cs(Because I'm not using StartUri):
_mainView.Resources.Source = new Uri("pack://application:,,,/App;component/Resources/DarkTheme.xaml"); // Colors and brushes
ResourceDictionary style = new ResourceDictionary
{
Source = new Uri("pack://application:,,,/App;component/Resources/Style.xaml")
};
_mainView.Resources.MergedDictionaries.Add(style); // Styles

Related

WPF Styles based on parent styles

Suppose I have a WPF style for a container element such as a grid which applies styles to its child items automatically, like this:
<Window.Resources>
<Style TargetType="Grid" x:Key="FormStyle">
<Style.Resources>
<Style TargetType="Label">
<Setter Property="FontSize" Value="50"/>
</Style>
</Style.Resources>
</Style>
</Window.Resources>
How can I then override certian elements of that style within the grid itself? For example suppose I wanted one grid to have FormStyle but also have a blue label, like this (which doesnt work):
<!-- this works fine and Label size = 50 -->
<Grid Style="{StaticResource FormStyle}">
<Label Content="Blah"/>
</Grid>
<!-- But this doesnt, label is blue, but normal font size -->
<Grid Style="{StaticResource FormStyle}">
<Grid.Resources>
<Style TargetType="Label" BasedOn="{StaticResource {x:Type Label}}">
<Setter Property="Foreground" Value="Blue"/>
</Style>
</Grid.Resources>
<Label Content="Blah"/>
</Grid>
I am expecting the BasedOn={StaticResource {x:Type Label}} to refer to the current active style for Labels at the current scope - i.e. the label style within FormStyle. But it clearly doesnt and refers to the base outer label style.
If I do for instance this globally
<Style TargetType="Label">
<Setter Property="FontSize" Value="50"/>
</Style>
Then it is all fine.
I could of course just name the styles, but surly there must be an easier/less verbose way?
Thanks
Here is the lookup process for Static Resources:
The lookup process checks for the requested key within the resource
dictionary defined by the element that sets the property.
The lookup process then traverses the logical tree upward to the
parent element and its resource dictionary. This process continues
until the root element is reached.
App resources are checked. App resources are those resources within
the resource dictionary that is defined by the Application object
for your WPF app.
In your case to resolve BasedOn="{StaticResource {x:Type Label}}" WPF first looks in the ResourceDictionary defined inside of Grid, then in Window - the logical parent of the Grid - and it's Resources, and then finally in Application level resources. WPF will not find it anywhere - and defaults to the base style - due to the style being a nested style in FormStyle.
Read further about Static Resource Lookup Behavior on Docs.
To get the desired output, you could:
1) Move your Label style out of FormStyle and in to Window.Resoruces
2) Merge the Label style from FormStyle into the Label style defined in the Grid element.
<Grid Style="{StaticResource FormStyle}">
<Grid.Resources>
<Style TargetType="Label">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="FontSize" Value="50"/>
</Style>
</Grid.Resources>
<Label Content="Blah"/>
</Grid>
3) Change your FormStyle not to have a nested style for Label, but to have setters for Label properties.
<Window.Resources>
<Style TargetType="Grid" x:Key="FormStyle">
<Setter Property="Label.FontSize" Value="50"/>
</Style>
</Window.Resources>

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>

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

Binding a WPF Style Trigger to a custom dependency property

I have found numerous similar threads here, but none that seem to address my specific issue.
I need to highlight the background of a textbox under certain conditions. I have created a Highlight property and tried using a trigger in a style to set it but it doesn't actually ever highlight the text.
Here is my Style, simplified:
<Style x:Key="TextBoxStyle" BasedOn="{StaticResource CommonStyles}">
<Style.Triggers>
<Trigger Property="Elements:DataElement.Highlight" Value="True">
<Setter Property="Control.Background"
Value="{DynamicResource EntryBoxHighlightBackground}"/>
</Trigger>
</Style.Triggers>
</Style>
Elements is defined as:
xmlns:Elements="clr-namespace:MDTCommon.Controls.Forms.Elements">
Then I have the section where the style is applied:
<!-- Applies above style to all TextBoxes -->
<Style TargetType="TextBox" BasedOn="{StaticResource TextBoxContentHolder}" >
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}" />
<!-- Overrides the default Error Style -->
</Style>
In the code behind of the DataElement class is the following:
public static readonly DependencyProperty HighlightProperty =
DependencyProperty.Register("Highlight", typeof(bool), typeof(DataElement));
public bool Highlight
{
get { return (bool)base.GetValue(HighlightProperty); }
set { base.SetValue(HighlightProperty, value); }
}
A DataElement ultimately derived from UserControl and it contains a reference to TextBox object as well as othe objects.
In the CustomForm class that houses all of the DataElement objects I have the following to set the color.
Resources["EntryBoxHighlightBackground"] = Brushes.Yellow;
So, the first issue is that setting the Highlight property for the DataElement doesn't cause the textbox background to draw in yellow.
The other issue is that I realize that I am applying this style to all textboxes and I could have textboxes in other areas that are not actually contained within a DataElement, which may cause a binding issue.
Try converting your trigger to a DataTrigger, and add a binding that will look directly at the DataElement control, like so:
<DataTrigger Binding="{Binding Path=Highlight, RelativeSource={RelativeSource AncestorType={x:Type Elements:DataElement}}}" Value="True">
<Setter Property="Control.Background" Value="{DynamicResource EntryBoxHighlightBackground}"/>
</DataTrigger>

How can styles be merged in Silverlight?

My goal is to extend the already set style of an object. So assuming I have the following two styles:
<Style TargetType="Ellipse" x:Key="OriginalStyle">
<Setter Property="Fill" Value="Blue"/>
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="200"/>
</Style>
<Style TargetType="Ellipse" x:Key="NewStyle">
<Setter Property="Fill" Value="Red"/>
</Style>
What I'd like to do is assign OriginalStyle to an Ellipse, then later apply the second style only changing the properties it affects. So ideally I want to do something like this:
Style OriginalStyle;
Style NewStyle;
Ellipse ellipse = new Ellipse();
ellipse .Style = OriginalStyle;
// Later in an event hanler
ellipse.Style = NewStyle; // I would want to keep the settings from the old style in here: in this example setting the style like this would make me lose the Width and Height properties!
I've tried to dynamically construct a new Style and add the properties of NewStyle and OldStyle - however the Property property of the styles are always null so this lead to a dead end:
Style combinedStyle = new Style();
foreach (Setter setter in Old.Setters)
{
combinedStyle.Setters.Add(setter); // Get exception "Element is already the child of another element."
}
foreach (Setter setter in NewStyle.Setters)
{
combinedStyle.Setters.Add(setter); // Get exception "Element is already the child of another element."
}
It seems like there is no way to dynamically merge styles in Silverlight. Could someone confirm this or show me a better approach to achieve merging?
Does "BasedOn" work in Silverlight? // wpf developer, never sure
You can do it simply like this:-
<Style TargetType="Ellipse" x:Key="OriginalStyle">
<Setter Property="Fill" Value="Blue"/>
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="200"/>
</Style>
<Style TargetType="Ellipse" x:Key="NewStyle" BasedOn="{StaticResource OriginalStyle}">
<Setter Property="Fill" Value="Red"/>
</Style>
Note that the order of appearance of such Style elements is important, you can not base a style on something that the XAML parser has not yet processed.

Resources