WPF style causing loop - wpf

Why does the following XAML cause a stack overflow exception with some themes?
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ExpressionLight.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style x:Key="BaseButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Margin" Value="5"/>
</Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource BaseButtonStyle}"/>
</ResourceDictionary>
</Application.Resources>
I have tried several themes found on internet and about half of them causes the exception.
Is there another way to apply a named Style as default?
Edit:
The problem is that the Theme adds the default style to the resource dictionary (an entry with the name System.Windows.Control.Button). Since a dictionary can only contain a single entry for each key it is not possible add a new default within the same resource dictionary.
Don't know why it leads to a "stackoverflow" instead of a "duplicate key" exception. It is probably because of the special handling of merged dictionaries which can contain duplicate keys.
The solution is to apply the named Style as default in code:
void AppStartup(object sender, StartupEventArgs args) {
this.Resources[typeof(Button)] = this.Resources["BaseButtonStyle"];
....
}
Since the BaseButtonStyle is staticly bound to the theme it is of course not possible to change theme at runtime with this solution.

you are having circular dependency in this code:
<Style x:Key="BaseButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Margin" Value="5"/>
</Style>
this style says that it is for TargetType Button, thats fine.
it also says that it is BasedOn the Style defined for TargetType Button, which is this itself.
Better to assign a key to the previous Style and then use that key in BasedOn.
EDIT:
After going through your code again it seems that there is a circular reference between your style and the style defined in ExpressionLight.xaml. A workaround would be to place resources at different levels.
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ExpressionLight.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.Resources>
<Style x:Key="BaseButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Margin" Value="5"/>
</Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource BaseButtonStyle}"/>
</Grid.Resources>
............
...........
...........
</Grid>

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>

Overriding single property setter from ResourceDictionary

I have a style defined in a file called MyStyles.xaml:
<Style TargetType="{x:Type igDP:XamDataGrid}">
<Setter Property="FontSize" Value="10" />
<Setter Property="FontFamily" Value="Arial" />
<EventSetter Event="CellUpdating" Handler="grid_CellUpdating"/>
</Style>
In one of my views, I have a XamDataGrid defined:
<igDP:XamDataGrid>
<igDP:XamDataGrid.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyProject.TheViews;component/Views/MyStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type igDP:XamDataGrid}" BasedOn="{StaticResource {x:Type igDP:XamDataGrid}}">
<Setter Property="FontSize" Value="70"/>
</Style>
</ResourceDictionary>
</igDP:XamDataGrid.Resources>
Basically, I want to keep everything that is defined in the style for XamDatagrid in MyStyles.xaml except for the font size, which I want to be set to 70.
I can't seem to get it to work. With the above, the font is set to 70 but I lose the other settings that are defined in MyStyles (such as the event handling and font family).
What am I doing wrong here?
(Extracting an answer from comments above.)
For overriding the style, I would suggest the following:
Define 2 styles in MyStyles.xaml: a named one which contains the style, and the unnamed one (this will be the default style) simply based on the named one
<Style x:Key="XamDataGridDefaultStyle" TargetType="{x:Type igDP:XamDataGrid}">
<Setter Property="FontSize" Value="10" />
<Setter Property="FontFamily" Value="Arial" />
<EventSetter Event="CellUpdating" Handler="grid_CellUpdating"/>
</Style>
<Style TargetType="{x:Type igDP:XamDataGrid}"
BasedOn="{StaticResource XamDataGridDefaultStyle}"/>
This will define the needed default style for all the views.
For the resources of the view where the customization is needed, define the following override:
<Style TargetType="{x:Type igDP:XamDataGrid}"
BasedOn="{StaticResource XamDataGridDefaultStyle}">
<Setter Property="FontSize" Value="70"/>
</Style>
You'll perhaps need to reference MyStyles.xaml as merged dictionary in the resources of the customized view for StaticResource to work.

Styles defined in Application.Resources not applying to controls

I am trying to apply global application styles to certain control types, however adding these styles to Application.Resources does is not applying the styles to the elements in my views.
Example:
<Application x:Class="GUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="AliceBlue"></Setter>
<Setter Property="Margin" Value="20,20,20,20"></Setter>
<Setter Property="FontStyle" Value="Italic"></Setter>
</Style>
</Application.Resources>
</Application>
In all the examples I have found for applying application wide styles this has been how they say to do it, however it is not working for me. What am I doing wrong?
Thanks,
Alex.
Worked this out myself woops, the problem is I was not using the StartUpUri property to open my initial application view, I changed my start up process so it does use this property and this has fixed my problem.
My App.xaml now looks like this:
<Application x:Class="GUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="/Views/Application/SplashView.xaml">
<Application.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="Aqua"></Setter>
</Style>
</Application.Resources>
</Application>
Thanks,
Alex.
Eventhough this is an old post and has been answered. I came across this problem. I removed StartupUri and added and empty style (I used the question as an example):
<Application x:Class="GUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<!-- Added blank style first -->
<Style TargetType="Rectangle" />
<Style TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="AliceBlue"></Setter>
<Setter Property="Margin" Value="20,20,20,20"></Setter>
<Setter Property="FontStyle" Value="Italic"></Setter>
</Style>
</Application.Resources>
</Application>

WPF style problem

I am actually using windows classic style in my applications by using the following declaration
<ResourceDictionary Source="/PresentationFramework.Classic;V3.0.0.0;31bf3856ad364e35;component/themes/classic.xaml" />
But whenever i declare a style to any of my controls say to set the font size and font family the appearance of the control also changes to suit the system theme and thus the control loses the classic appearance.
What could be happening?
I tried using
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}" >
to see if this helps me in getting back the classic theme. But it doesn't seem to work.
Try if this works
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/PresentationFramework.Classic;V3.0.0.0;31bf3856ad364e35;component/themes/classic.xaml" />
<ResourceDictionary>
<Style x:Key="ExtendedButtonStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="Red"/>
</Style>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Button Content="click" Height="30" Width="100" Style="{StaticResource ExtendedButtonStyle}"/>
</Grid>

Setting an Elements.Resource Style using BasedOn within a Resource Dictionary

I have a Resource Dictionary that I am using to define the look-and-feel (style) for my application.
I have just created another Resource Dictionary that contains DataTemplates that I am using on several different screens (and even multiple times within the same screen) to display my business objects.
I would like to change some of the default styles within my DataTemplates so that the controls fit better; however I would like the controls to inherit the same style as the rest of the screen. So, naturally I want to use the BasedOn property for this task.
The problem that I am having is that I'm not sure what to set the BasedOn property to.
For example, in the resource dictionary that contains my styles (called "myStyle.xaml") I have:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:primatives="clr-namespace:System.Windows.Controls.Primitives;assembly=PresentationFramework"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="{x:Type Label}">
<Setter Property="Foreground" Value="#F5F5F5" />
<Setter Property="FontSize" Value="12"></Setter>
<Setter Property="Width" Value="120"></Setter>
<Setter Property="FontFamily" Value="Arial"></Setter>
</Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="FontSize" Value="12"></Setter>
<Setter Property="Width" Value="120"></Setter>
<Setter Property="Height" Value="25"></Setter>
<Setter Property="Background" Value="Black"></Setter>
</Style>
<!-- .... and so on .... -->
</ResourceDictionary>
I am using this resource in the following window:
<Window x:Class="SiteSetupWindow4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:primatives="clr-namespace:System.Windows.Controls.Primitives;assembly=PresentationFramework"
Title="A Screen">
<Window.Resources>
<ResourceDictionary x:Key="defaultStyleX">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary x:Name="DefaultStyles" Source="Resources/myStyle.xaml" />
<ResourceDictionary x:Name="Templates" Source="Resources/myTemplates.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
Now, I have another Resource Dictionary that contains DataTemplates that I am using within my window. It is called "myTemplates". The style is applied to the DataTemplate as expected; however, I would like to overwrite some aspects of the style within the DataTemplate (Like width for example).
This is what I have tired, however I cannot get the BasedOn property to work...
(myTemplate.xaml)
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DataTemplate x:Key="PanelInfo">
<StackPanel>
<StackPanel.Resources>
<Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Width" Value="120" />
</Style>
<Style TargetType="Label">
<Setter Property="Width" Value="180" />
</Style>
<Style TargetType="ComboBox">
<Setter Property="Width" Value="120" />
</Style>
<StackPanel.Resources>
<StackPanel Orientation="Horizontal">
<Label Content="Type:"></Label>
<ComboBox>
<ComboBoxItem Content="{Binding Path=Type}" IsSelected="True"></ComboBoxItem>
</ComboBox>
<!--...and so on -->
</StackPanel>
</StackPanel>
</ResourceDictionary>
This fails....I have also tried using DynamicResource, but this also fails.
I'm not sure how to get around this.
Any advise would be greatly appreciated!
Thanks,
-Frinny
I was having the same problem with an extended Button Style.
The ResourceKey= is what solved it for me.
This worked:
<Style x:Name="ButtonVisibility"
TargetType="{x:Type Button}"
BasedOn="{StaticResource ResourceKey={x:Type Button}}">
The way you have BasedOn for a type is correct. This will work in theory as long as, at run time, the style that you are basing it on is merged into the tree correctly. Make sure you have the "myStyles.xaml" merged in correctly. You can check this by removing your style you tried to modify and make sure it displays correctly from your style in "myStyles.xaml."
If it isn't there are a lot of places you can go wrong, but it always helps to try merging the styles in the file you are working on, then work up the tree to see where it's missing.
This utility will help you look at what is happing in the tree at run time.
http://blois.us/Snoop/

Resources