Inheriting from Application Styles (WPF) - wpf

I am trying to inherit application-level styles for a certain Window in my WPF application, but I'm having trouble getting it to inherit rather than simply override the existing styles.
In App.xaml (under the App.Resources element) I define a style as such:
<Style TargetType="Button">
<Setter Property="Padding" Value="6"/>
<Setter Property="FontWeight" Value="Bold"/>
</Style>
And in the XAML fora a certain Window, I define the following under Window.Resources:
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Padding" Value="6"/>
<Setter Property="FontWeight" Value="Bold"/>
</Style>
The problem here is that the former (app) style is ignored as if the latter (window) style has overridden it. The BasedOn attribute is set, which is intended to indicate that existing styles should be inherited, as far as I know. Removing the attribute doesn't help either. The only potential cause of which I can think is that {StaticResource {x:Type Button}} only refers to the default WPF style and not the one I have define in App.xaml.
I am aware that this styling behaviour would be possible to accomplish using the x:Key attribute, but I was hoping for a more elegant way that allows me to apply styles with inheritance to all controls within a scope (i.e. application/window).
Update
Thanks for both of your replies. You are indeed right that things work as expected in a sample application. The difference is that I inadvertently failed to mention that the style in App.xaml is contained within a ResourceDictionary, as such:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="SettingsDictionary.xaml"/>
<ResourceDictionary>
<Style x:Key="DefaultButton" TargetType="Button">
<Setter Property="Padding" Value="4"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Any suggestion on how to remedy matters in this case?

EDIT
After some research, I've found that the x:Key is being automatically generated if TargetType is set. So, the style in App.xaml is correct. However, the wpf designer is lacking some resource handling skills, and is not displayng both styles. If you build and run the project, both styles will be applied.
If your machine and VS2008 behave like the one upon which I tested your code.
Hope this helps.
EDIT 2
The resources and merged dictionaries in App.xaml have always been quirky.
I've solved the problem by moving the first style declaration out of the merged dictionary, like this:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!--<ResourceDictionary Source="SettingsDictionary.xaml"/>-->
</ResourceDictionary.MergedDictionaries>
<Style TargetType="Button">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="Padding" Value="4"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
</ResourceDictionary>
</Application.Resources>
Note also that giving the style an explicitly set key other than the {x:Type Button} will make it a non-default style and make it not apply automatically.
It is generally recommended to specify merged dictionaries only for resources from another file, and coded resources in the default space as above.

I'd second Jeff Wains comment in being surprised that your approach is not working as desired. In fact I'm unable to reproduce your issue via the following steps:
Created a new project via VS 2008 C# WPF application wizard.
resulting in App.xaml and Window1.xaml just like your example
Added a standard button from the toolbox to Window1.
Pasted your snippets as is, but modified one property each to observe the desired effect in the first place (having identical properties/values each is not what you intended to demonstrate I guess).
Well, this is just working fine, i.e. the button in Window1 inherits properties from both styles and modifying properties in either one does properly affect the button. Consequently their must be something weird going on behind the scenes in your project/environment? Have you tried a simple repro case like this already?

Related

Set default Style for FrameworkElement is not applied to derived class

I am a beginner in XAML. I create a new default style in a ResourceDictionary.
<Style TargetType="FrameworkElement" BasedOn="{StaticResource {x:Type FrameworkElement}}">
<Setter Property="Margin" Value="5"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
Then I import it to UserControl.Resources.
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/PathToStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
What I expect is that it will be applied to all FrameworkElements used in that UserControl, but it is not.
What infomation am I missing here?
The problem is because TargetType is specific.
A style which you do not give a x:Key to automatically is given a key which is equivalent to it's type.
Hence your style:
<Style TargetType="FrameworkElement"
Actually has an x:Key given to it which is
<Style x:Key="{x:Type FrameworkElement}"
https://learn.microsoft.com/en-us/dotnet/api/system.windows.style.targettype?redirectedfrom=MSDN&view=netcore-3.1#System_Windows_Style_TargetType
A piece of ui which is "looking" for a style looks for a matching key to it's type using that x:Key. It does not search up it's inheritance chain as well.
EDIT:
You can prove this:
In a new wpf app, add a frameworkelement to you mainwindow and a style targets frameworkelement.
<Window.Resources>
<Style TargetType="FrameworkElement">
<Setter Property="Height" Value="10"/>
</Style>
</Window.Resources>
<Grid>
<local:TestSubClass/>
</Grid>
and
public class TestSubClass : FrameworkElement
Spin it up and take a look at the live visual tree > Properties.
The frameworkelement fills the grid and has an actualheight matching the grid's height.
No style is set on it.
Hence this is the situation where no style is set and inheritance is not working as claimed in another post.
Change that to a regular frameworkelement:
<Window.Resources>
<Style TargetType="FrameworkElement">
<Setter Property="Height" Value="10"/>
</Style>
</Window.Resources>
<Grid>
<FrameworkElement/>
</Grid>
Spin it up with an f5 and take a look at the live visual tree.
There is a style in the properties.
Actualheight is 10.
What I'm expecting is it will apply to all FrameworkElement used in That UserControl
By all FrameworkElements you probably mean all FrameworkElements including its derivatives. Applying the Style as implicit style works perfectly if you target a distinct control like a Button. However, it may not work as you expect, if you target a base type of a control, like FrameworkElement, because each derivative of that base type can have their own style applied explicitly or implicitly that breaks your anticipated behavior by:
Not being based on the style of the base type
Not being based on a style that is transitively based on the base type style
Overriding the properties of the base style
The essential misunderstanding here is that all styles of derivatives of a base type will base their style on the style of said base type, but this does not apply in general.
You can check this yourself by extracting the Style of any control via Visual Studio or Blend. For example, let's look at the Style of a Button. As you can see, it is not even based on FrameworkElement, so it will not apply your base style. Even if it would, there is a chance that it will override the Margin property itself.
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
<Setter Property="Background" Value="{DynamicResource PrimaryHueMidBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource PrimaryHueMidBrush}"/>
<!-- ...other setters. -->
</Style>
Apart from that, you have to define your base type style before any other styles of derivatives, because you can only use BasedOn with StaticResource. Consequently, if the style of a derived control is already defined before your style, your base style will not be applied.
What infomation am I missing here?
The fact that there are default styles defined for more derived types such as for example Button and Control and that these will take precedence over and be applied instead of your custom FrameworkElement style.
Your approach of defining a single Style for all FrameworkElements won't work. You'll need to define an implicit type for each derived FrameworkElement type.

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.

Implicity style for BarDataPoint is not applied

I am currently working on creating a theme for charts.
Beside other things, I want to make the bars in BarSeries have a flat look(without borders).
I want to make it to work with implicit styling so I added a Style to BarDataPoint(without a Key because it needs to work by implicit styling) but it is not applied.
Any idea why is it is not applied?
Is it because of DataPointStyle style from Palette which is applied instead?
What I am trying to do is to change the look of the BarDataPoint but still have the colors from the palette applied. And also try to make this work by pure XAML(if possible).
In order to make this work, the only way I see is by changing DataPointStyle(in each ResourceDictionary from Chart.Palette) to have TargetType set to BarDataPoint and Template set to my template implementation:
<toolkit:Chart.Palette>
<toolkit:ResourceDictionaryCollection>
<ResourceDictionary>
<Style x:Key="DataPointStyle" TargetType="toolkit:BarDataPoint" BasedOn="{StaticResource BarDataPointStyle}">
<Setter Property="Background" Value="Yellow" />
<Setter Property="BorderBrush" Value="Black" />
</Style>
</ResourceDictionary>
<ResourceDictionary>
<Style x:Key="DataPointStyle" TargetType="toolkit:BarDataPoint" BasedOn="{StaticResource BarDataPointStyle}">
<Setter Property="Background" Value="Red" />
<Setter Property="BorderBrush" Value="Black" />
</Style>
</ResourceDictionary>
</toolkit:ResourceDictionaryCollection>
</toolkit:Chart.Palette>
But since this is for implicit style for Chart control, how would that work if I have a Char control with a different type of series, for example a Chart with ColumnSeries? I don't think the DataPointStyle will work in this case because it is targeting the BarDataPoint type(I suppose the app will crash).
Am I forced to create different Chart styles with different keys(each style having DataPointStyle changed to target different control template)?
But then, how will that work for a Chart control with several different series?
I also tried to use an implicit style for toolkit:BarDataPoint in the palette's resource dictionary like this, but without success:
<Setter Property="Palette">
<Setter.Value>
<toolkit:ResourceDictionaryCollection>
<ResourceDictionary>
<SolidColorBrush x:Key="Background"
Color="#FFCA294D" />
<Style TargetType="toolkit:BarDataPoint">
<Setter Property="Template"
Value="{StaticResource BarDataPointTemplate}" />
<Setter Property="Background"
Value="{StaticResource Background}" />
</Style>
I tried to look to themes like JetPack but they don't seem to do what I want.
Thanks!
sorry for late update.
check this solution. may help others too
Silverlight 4: Chart Toolkit Color Set

How do I alter the default style of a button without WPF reverting from Aero to Classic?

I've added PresentationFramework.Aero to my App.xaml merged dictionaries, as in...
<Application
x:Class="TestApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="/PresentationFramework.Aero;component/themes/Aero.NormalColor.xaml" />
<ResourceDictionary
Source="pack://application:,,,/WPFToolkit;component/Themes/Aero.NormalColor.xaml" />
<ResourceDictionary
Source="/CommonLibraryWpf;component/ResourceDictionaries/ButtonResourceDictionary.xaml" />
<!-- Note, ButtonResourceDictionary.xaml is defined in an external class library-->
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
I'm trying to modify the default look of buttons just slightly. I put this style in my ButtonResourceDictionary:
<Style TargetType="Button">
<Setter Property="Padding" Value="3" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
All buttons now have the correct padding and bold text, but they look "Classic", not "Aero". How do I fix this style so my buttons all look Aero but also have these minor changes? I would prefer not to have to set the Style property for every button.
Update
I should have mentioned this in the first place, but if I try to use BasedOn, as shown below, I get a StackOverflowException:
<Style BasedOn="{StaticResource {x:Type Button}}" TargetType="{x:Type Button}">
<Setter Property="Padding" Value="3" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
This would normally work, but not with the Aero dictionaries merged in. If I comment those dictionaries out, the exception disappears.
Update 2
If I add an x:Key attribute and manually set the style, it works properly (Aero style with padding and bold), but as I said, I'd prefer that the style is automatically applied globally to all buttons.
Update 3
I just discovered a new wrinkle. In my app, ButtonResourceDictionary.xaml is placed in a class library (i.e., in an external project). If I move this file to a local folder, everything works fine. So, the problem seems to be a bad interaction caused by referencing various external resource dictionaries. I'm correcting my App.xaml code snippet (above) to reflect that ButtonResourceDictionary is actually defined externally.
I hope you've found a solution in the meantime. For everyone else, here is one workaround, and here is another. I am not sure whether this will help for your specific case though (especially the fact that you reference an embedded resource dictionary).
UPDATE
Here's a solution I came up with:
<Style TargetType="TextBox" BasedOn="{Common:StaticApplicationResource {x:Type TextBox}}">
<Setter Property="Height" Value="21"/>
</Style>
Where StaticApplicationResource is a custom MarkupExtension I wrote that simply calls TryFindResource:
[MarkupExtensionReturnType(typeof(object))]
public class StaticApplicationResource : MarkupExtension
{
public StaticApplicationResource(object pResourceKey)
{
mResourceKey = pResourceKey;
}
private object _ResourceKey;
[ConstructorArgument("pResourceKey")]
public object mResourceKey
{
get { return _ResourceKey; }
set { _ResourceKey = value; }
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (mResourceKey == null)
return null;
object o = Application.Current.TryFindResource(mResourceKey);
return o;
}
}
This way I don't have to reference my resource dictionaries outside of my App.xaml file , which is the way I like it :). You can also put more complicated logic in there too, allowing you to resolve the BasedOn style any way you like. Here is an excellent article showing you how to load resource dictionaries (and those that the framework resolves automatically) from code.
Based on your updates, you could do this (admittedly it is hideously ugly):
<Style x:Key="_buttonStyleBase"
BasedOn="{StaticResource {x:Type Button}}"
TargetType="{x:Type Button}">
<Setter Property="Padding" Value="3" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style TargetType="{x:Type Button}"
BasedOn="{StaticResource _buttonStyleBase}" />
Use the BasedOn attribute to inherit the properties from the Aero Style. This should solve your problem.
<Style
BasedOn="{StaticResource {x:Type Button}}"
TargetType="{x:Type Button}">
<Setter Property="Padding" Value="3" />
<Setter Property="FontWeight" Value="Bold" />
</Style>

WPF: How do I inherit property values to all child controls?

I have UserControls containing other controls. I want that if I set a Foreground color for the UserControl, all child controls automatically inherit it. I have the same problem with font style/size.
Can I set these properties somehow to auto/inherit? Is this possible to set all subcontrols without a loop?
You can you create resource dictionaries to define default styles globally.
You can also reference a resource dictionary or define a style in any object.
In either case those styles will apply to all child objects that don't have a style explicitly defined...
Example:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<!--Default styles that will apply to any object of the specified type (if it doesn't have style set locally)-->
<Style TargetType="Label" >
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
</Style>
</ResourceDictionary>
Look into using Styles and BasedOn settings.
I recently wrote an example of something similar located here. Unfortunally the question was related to Silver Lite so didn't answer the question, but I think it may give you some ideas on where to look.

Resources