Overriding application wide style - wpf

I want to define a global style for textblock in the application but I also want to be able to override this default style. I always thought that the local override of style has more priority than the global one but it doesn't seems to be the case?
In the following example, the Button with content "Test" will have a "Red" foreground when I expect it to be "Aqua". If I remove the global style in Application.Resources, than it will works. Did I'm missing something?
App.xaml
<Application x:Class="ContextMenuTest.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Red" />
</Style>
</Application.Resources>
MainWindow.xaml
<Window x:Class="ContextMenuTest.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">
<Window.Resources>
<Style TargetType="{x:Type MenuItem}" x:Key="DefaultMenuItemStyle">
<Setter Property="Foreground" Value="DarkGreen" />
</Style>
<Style TargetType="{x:Type Button}" x:Key="DefaultButtonStyle">
<Setter Property="Foreground" Value="DarkGreen" />
</Style>
</Window.Resources>
<Grid Background="Black">
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Header="Menu 1" Style="{StaticResource DefaultMenuItemStyle}" />
<MenuItem Header="Menu 2" Style="{StaticResource DefaultMenuItemStyle}" />
<MenuItem Header="Menu 3" Style="{StaticResource DefaultMenuItemStyle}" />
<MenuItem Header="Menu 4" Style="{StaticResource DefaultMenuItemStyle}" />
<MenuItem Header="Menu 5" Style="{StaticResource DefaultMenuItemStyle}" />
</ContextMenu>
</Grid.ContextMenu>
<Button Content="Test" Style="{StaticResource DefaultButtonStyle}" Foreground="Aqua" />
</Grid>

Implicit TextBlock defined in App.xaml will not be overrided by other TextBlock styles. It's therefore recommended that you move your default TextBlock style to for example <Window.Resources>.
Please refer to the following links for more information about this.
Implicit styles in Application.Resources vs Window.Resources?
Over ride the Property setting in App.xaml: https://social.msdn.microsoft.com/Forums/vstudio/en-US/f6822a5e-09c7-489b-b85d-833f1f9356dc/over-ride-the-property-setting-in-appxaml?forum=wpf
Or simply don't define any implicit TextBlock style. Define a default Style for each Control instead.

Your problem is in defining your application level resources for the TextBlock instead of the Button. Most of WPF controls use TextBlocks as default way to display text content, so by trying to override your Button Foreground, you are doing it, but then it gets overriden again by TextBlock default style.
Change your App.xaml to this and you will get the result you wanted to achieve:
<Application.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="Red" />
</Style>
</Application.Resources>

Related

Extend style without setting an x:Key attribute in the base style

I have a file MyButtonStyles.xaml which designs the WPF button. This file uses a style to set some colors and fonts:
<ResourceDictionary xmlns......>
<Style BasedOn="{StaticResource {x:Type Button}} TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="Blue" />
<Setter Property="FontSize" Value="22" />
</Style>
</ResourceDictionary>
This button is used in two xaml files. One shows the button as designed in the above style. This happens automatically because the above style has the according TargetType and it does not have an x:Key attribute.
In the other xaml file I use this button as well but the style from above should be extended by another setter property. Doing this by merging the dictionaries and basing on the original style it works:
<ResourceDictionary>
<ResourceDictionary.MergedDictionary>
<ResourceDictionary Source="MyButtonStyles.xaml" />
<ResourceDictionary.MergedDictionary>
<Style BasedOn="ButtonStylesOrig" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Green" />
</Style>
</ResourceDictionary>
But for this I have to add an x:Key attribute (ButtonStylesOrig) to the base style. This means that in the first xaml which uses the button the base style will not be applied any more.
Is there a possibility to extend a style without losing the global scope of it (e.g. without using x:Key)?
This works:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="MyButtonStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Background" Value="Green" />
</Style>
</Grid.Resources>
<Button Content="Button" />
</Grid>
</Window>
The key is not to override the resource in the same resource dictionary that you merge your base style into:
WPF Using multiple Resource Dictionaries from multiple projects
You can't combine multiple default styles of the same type a single resource scope. However, it is possible to build default styles in nested resource scopes.
Suppose you merge MyButtonStyles.xaml into the App.xaml resources. Then you can place your second style with the additional setter into Window.Resources or other deeper nested resources and it will combine the correct implicit styles.
A more localized example:
<Grid>
<Grid.Resources>
<ResourceDictionary Source="MyButtonStyles.xaml"/>
</Grid.Resources>
<Grid>
<Grid.Resources>
<Style BasedOn="{StaticResource {x:Type Button}}" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Green" />
</Style>
</Grid.Resources>
<Button VerticalAlignment="Top" Margin="20">Both styles</Button>
</Grid>
<Button VerticalAlignment="Center" Margin="20">ExampleDictionary style</Button>
</Grid>

Possible to create an implicit style that is used, by default, as the base for other styles?

I'm trying to figure out a way to create an implicit style for a custom control, that will be inherited by other styles applied to the control.
For example, let's say I have a control FancyButton. Then I can define an implicit style by putting this in my app resources:
<Style TargetType="my:FancyButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="my:FancyButton">
<TextBlock Text="hello world" Foreground="{TemplateBinding Foreground}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then users of the control will see "hello world" in green just by writing:
<my:FancyButton Foreground="Green" />
The problem is, if someone wants to define a green-colored style like this ...
<Style TargetType="my:FancyButton" x:Key="GreenButton">
<Setter Property="Foreground" Value="Green" />
</Style>
<my:FancyButton Style="{StaticResource GreenButton}" />
... then they will have lost the implicit style's control template, and will not see the "hello world".
Of course, you can define a base style, which the implicit style inherits ...
<Style TargetType="my:FancyButton" x:Key="FancyButtonDefaultStyle">
<!-- ... -->
</Style>
<Style TargetType="my:FancyButton" BasedOn="{StaticResource FancyButtonDefaultStyle}">
</Style>
... and that way users of the control can inherit the default style:
<Style TargetType="my:FancyButton" x:Key="GreenButton" BasedOn="{StaticResource FancyButtonDefaultStyle}">
<Setter Property="Foreground" Value="Green" />
</Style>
But it seems awkward to force users of the control to remember to inherit a default style based on a key. Isn't there some way to make a custom control's styles inherit the implicit style, in the same way that the framework controls do?
Ie, I want my FancyButton to behave in the same way a Button does, where I can define a style that doesn't wipe out the other default style properties (esp. ControlTemplate):
<Style TargetType="Button" x:Key="GreenButton">
<Setter Property="Foreground" Value="Green" />
</Style>
You need to put the implicit style definition
<Style TargetType="my:FancyButton">
<!-- etc -->
</Style>
in the special "Themes/Generic.xaml" resource dictionary (in the same assembly as where the control class is defined). This makes all styles inherit from the implicit style, as you wanted.
Sorry for quoting. :)
Hope this helps.
Here's my code:
MainPage.xaml:
<UserControl x:Class="SilverlightApplication4.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SilverlightApplication4"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<UserControl.Resources>
<ResourceDictionary>
<Style TargetType="local:TemplatedControl1"
x:Key="myCustomTemplate">
<Setter Property="Foreground"
Value="Purple" />
</Style>
</ResourceDictionary>
</UserControl.Resources>
<Grid x:Name="LayoutRoot"
Background="Yellow"
Width="500"
Height="500">
<local:TemplatedControl1 Style="{StaticResource myCustomTemplate}" />
</Grid>
</UserControl>
Now in TemplatedControl.cs don't forget to put this:
this.DefaultStyleKey = typeof(TemplatedControl1);
And finally put your implicit style definition in Themes\Generic.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SilverlightApplication4">
<Style TargetType="local:TemplatedControl1">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:TemplatedControl1">
<TextBlock Text="hello world"
Foreground="{TemplateBinding Foreground}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
With this method, the result should be purple text in a terrible yellow background. :)
Thanks to #Tanis83 for pointing out the (very simple) answer. I just needed to put the implicit style ...
<Style TargetType="my:FancyButton">
<!-- etc -->
</Style>
in the special "Themes/Generic.xaml" resource dictionary (in the same assembly as where the control class is defined). This makes all styles inherit from the implicit style, as I wanted.

How to apply DependencyProperty values to child user controls?

I have multiple instances of the same custom user control in a StackPanel. Each instance needs the same DependencyProperty "ControlWidth". Instead of setting each user control with the same property, I want to set it only once in the parent StackPanel
<StackPanel>
<propwin:PropertyEditControl Label="First" ControlWidth="180" />
<propwin:PropertyEditControl Label="First" ControlWidth="180" />
...
</StackPanel>
I used to do this with Style properties
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type propwin:PropertyEditControl}">
<Setter Property="ControlWidth" Value="180" />
</Style>
</StackPanel.Resources>
<propwin:PropertyEditControl Label="First" />
<propwin:PropertyEditControl Label="Second" />
...
</StackPanel>
Update:
Thanks to Anatoliy, who mention that my code (the one I showed here) should work. I now tracked down the problem. Inside my PropertyEditControl.xaml I define a validation style:
<UserControl x:Class="MyModule.PropertyEditControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyModule">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyModule;component/UI/ResourceDictionaries/ResourceLibrary.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="local:PropertyEditControl">
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ValidationErrorTemplate}" />
</Style>
<Style x:Key="PropertyNameStyle" TargetType="DockPanel">
<Setter Property="Width" Value="{Binding ControlWidth}" />
<Setter Property="DockPanel.Dock" Value="Left" />
</Style>
...
If I remove the <Style TargetType="local:PropertyEditControl"> style it works!
It turned out that my original approach should have worked. The reason why it hasn't was a misplaced Style Resource inside the user control. Anyway, the correct answer to my initial question is: To set a DependencyProperty value for multiple controls only once, you have to set it inside the container style definition:
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type propwin:PropertyEditControl}">
<Setter Property="ControlWidth" Value="180" />
</Style>
</StackPanel.Resources>
<propwin:PropertyEditControl Label="First" />
<propwin:PropertyEditControl Label="Second" />
...
</StackPanel>

How to set a default Margin for all the controls on all my WPF windows?

I want to set a default Margin of 3 on all the controls I put on all my windows and be able to override this value just on a really few number of items.
I've seen some approaches like doing styles but then I need to style everything, I would prefer something than can be done for all the controls together. I've seen other things like the MarginSetter but looks like it does not traverse subpanels. I want the Margin only on the controls I put at the window, nothing to do with the borders or other things of the visual tree.
Looks something pretty basic to me. Any ideas?
Thanks in advance.
The only solution I can find is to apply the style to each of the controls you are using on the window (I know that's not quite what you want). If you're only using a few different control types it's not too onerous to do something like this:
<Window x:Class="WpfApplication7.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">
<Window.Resources>
<!-- One style for each *type* of control on the window -->
<Style TargetType="TextBox">
<Setter Property="Margin" Value="10"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="Margin" Value="10"/>
</Style>
</Window.Resources>
<StackPanel>
<TextBox Text="TextBox"/>
<TextBlock Text="TextBlock"/>
</StackPanel>
</Window>
Good luck...
You can link all of your Margin properties by referring to a "Thickness" defined in your resources. I just did this in a project...
<!-- somwhere in a resource-->
<Thickness x:Key="CommonMargin" Left="0" Right="14" Top="6" Bottom="0" />
<!-- Inside of a Style -->
<Style TargetType="{x:Type Control}" x:Key="MyStyle">
<Setter Property="Margin" Value="{StaticResource CommonMargin}" />
</Style>
<!-- Then call the style in a control -->
<Button Style="{StaticResource MyStyle}" />
<!-- Or directly on a Control -->
<Button Margin="{StaticResource CommonMargin}" />
The key for me was figuring out that Margin was defined by "Thickness". Let me know if that's clear enough or if you need me to put it in a fully working XAML example.
You can apply margin in your buttons style. And when you use buttons with this style in StackPanel wpf will apply need spacing.
for example
define in resourcedictionary or whatever:
<Style x:Key="myButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Margin" Value="10"/>
....
</Style>
then in yor StackPanel xaml definition:
<StackPanel>
<Border BorderThickness="0"/>
<Button x:Name="VertBut1" Style="{StaticResource myButtonStyle}" Content="Button1"/>
<Button x:Name="VertBut2" Style="{StaticResource myButtonStyle}" Content="Button2"/>
<Button x:Name="VertBut3" Style="{StaticResource myButtonStyle}" Content="Button3"/>
</StackPanel>
regards
Georgi

WPF UserControl Style -- How do I set the style from the parent if the control is in an external assembly?

Basically I have the following structure:
<Window ...
xmlns:my="http://schemas.company.com/WPF/Controls"
>
<Window.Resources>
<Style x:Key="MyStyle1" TargetType={x:Type TextBlock}>
...
</Style>
</Window.Resources>
<Grid x:Name="LayoutRoot">
<my:MyUserControl1 />
<my:MyUserControl1 />
<my:MyUserControl2 />
<my:MyUserControl2 />
</Grid>
</Window>
<UserControl ...
>
<TextBlock Style={ ?? What Goes Here ??} />
</UserControl>
How do I apply the style declared in the Window resources so that it goes to the UserControl that is being pulled from an external assembly?
If you want the Style to be applied to all TextBlocks, including the ones in MyUserControl, just leave the x:Key out and it will be applied implictly
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Green"/>
</Style>
If you want it to be set explicitly you can use DynamicResource in the UserControls
<Window.Resources>
<Style x:Key="MyStyle1" TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Green"/>
</Style>
</Window.Resources>
<StackPanel>
<my:UserControl1 />
<my:UserControl1 />
<my:UserControl1 />
<my:UserControl1 />
</StackPanel>
<UserControl ...>
<TextBlock Style="{DynamicResource MyStyle1}" Text="TextBlock"/>
</UserControl>
Try this :
<TextBlock Style={ StaticResource MyStyle1} />
I hope this help you Introduction to Styles in WPF

Resources