Style inheritance based on different XAML - c#

How to specify BasedOn tag in a style to a style defined in some other file.
Example,
Dictionary1.xaml defines
<Style x:Key="basicStyle" TargetType="TextBlock" >
<Setter Property="FontSize" Value="24"></Setter>
<Setter Property="Foreground" Value="DarkGray"></Setter>
<Setter Property="FontWeight" Value="Bold"></Setter>
</Style>
In Dictionary2.xaml i need something like
<Style x:Key="headerStyle" TargetType="TextBlock" >
<Setter Property="FontSize" Value="46"></Setter>
<Setter Property="Foreground" Value="DarkGray"></Setter>
<Setter Property="FontWeight" Value="Bold"></Setter>
</Style>
How to achieve this?

The easy way:
In Dictionary2.xaml define MergedDictionaries (right after the opening ResourceDictionary tag):
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Path/to/Dictionary1.xaml" />
</ResourceDictionary.MergedDictionaries>
And then
<Style x:Key="headerStyle" TargetType="TextBlock" BasedOn="{StaticResource basicStyle}" >
.....
</Style>
This will solve the issue, but as with all easy solutions there's a catch: each time you merge dictionaries you effectively create a copy of the merged dictionary. And it's recursive - if you have Dict3.xaml and Dict4.xaml that both load Dictionary2.xaml, you will have three instances of Dictionary1.xaml created. With a complex dependency structure you can get to a point that you have 19,000+ dictionary objects in memory at application start up and the memory footprint goes from 180MB to 1200MB (TrueStory™ :( ).
The solution is a SharedResourceDictionary. The implementation in the tutorial should be seen as a starting point and will probably need some level of tweaking - depending on use scenario. Google "wpf SharedResourceDictionary" for some gotchas and solutions.

Related

What is the correct way to change the Value of multiple Styles?

I am currently trying to implement a Dark Mode to my application. I have multiple ResourceDictionaries, one Window and multiple UserControls. In my MainWindow I've created a Command that is supposed to change the Design during runtime.
One of my ResourceDictionaries looks like this:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="SecondaryBorder" TargetType="Border">
<Style.Setters>
<Setter Property="Background" Value="#272726"/>
</Style.Setters>
</Style>
<Style x:Key="WindowTheme" TargetType="Window">
<Style.Setters>
<Setter Property="Background" Value="#3c3c3b"/>
</Style.Setters>
</Style>
<Style x:Key="HeadlineReports" TargetType="TextBlock">
<Style.Setters>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontSize" Value="20"/>
<Setter Property="FontFamily" Value="Rubik Light"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
</Style.Setters>
</Style>
</ResourceDictionary>
Here I would like to change the following values: #272726 → #55ffff and #3c3c3b → #FFFFFF.
At first, I thought that I could create a global value for each colour and simply change the value with code-behind, however, I now learned that you are not supposed to do that with ResourceDictionaries.
What would be the correct way to change the colour throughout the whole application?
Create a copy of the existing ResourceDictionary and edit the values in this copy.
When you want to switch theme, you then remove the existing resource dictionary and merge the new one. Something like this:
App.Current.Resources.MergedDictionaries.Clear();
App.Current.Resources.MergedDictionaries.Add(new ResourceDictionary()
{
Source = new Uri("dark.xaml")
});

How to easily allow users to update Styles used be elements in XAML (UWP)

This is for a Windows 10 UWP. I need to allow users to update values on Styles that are associated with elements used throughout the application (i.e allow users to change the font size of various textblocks, background color stackpanels etc.) .
I currently have all my Styles in a separately file.
My App.xaml is as below:
<Application
x:Class="MyTestApp.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="/Styles/Styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
My Styles.xaml (partial) is as below:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:MyTestApp.Views"
xmlns:x1="using:System">
<Style x:Key="HeaderTextBlocks" TargetType="TextBlock" BasedOn="{StaticResource TitleTextBlockStyle}">
<Setter Property="FontSize" Value="24"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="TextWrapping" Value="NoWrap"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="Margin" Value="10,4,0,0"/>
</Style>
<Style x:Key="RegularTextBlocks" TargetType="TextBlock" BasedOn="{StaticResource TitleTextBlockStyle}">
<Setter Property="FontSize" Value="12"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="TextWrapping" Value="NoWrap"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="Margin" Value="0,0,0,0"/>
</Style>
</ResourceDictionary>
I refer to these styles on controls throughout the application using like this:
<TextBlock Style="{StaticResource HeaderTextBlocks}" />
I have created a Settings page (settings.xaml) which has textboxes for the users to update various style settings.
But I am not sure how I could bind these to the settings on the various styles on the styles.xaml file so that the styles are updated and the controls referring to the styles are updated when the user changes the value.
<TextBox Header="Font Size of Header TextBlocks" Text="{x:Bind HeaderTextBlocks.FontSize ???, Mode=TwoWay}" />
<TextBox Header="Font Size of Regular TextBlocks" Text="{x:Bind RegularTextBlocks.FontSize???, Mode=TwoWay}" />
Could someone please point me in the right direction? I am trying to do this with minimal (or no code behind) as possible.
Unfortunately this kind of user-defined styling is not easily available in UWP. You can however implement a kind of styling solution using data binding.
First step is to create a class like CustomUISettings which implements INotifyPropertyChanged and has properties like HeaderFontSize, etc.
Now on app start create an instance of this class and add it as app resource:
Application.Current.Resources["CustomUISettings"] = new CustomUISettings();
Now you can bind to the properties in this class anywhere in your code:
<TextBox FontSize="{Binding HeaderFontSize, Source={StaticResource CustomUISettings}}" />
You must use the classic {Binding} markup extension, because {x:Bind} does not support Source setting.
To modify the UI settings you can just retrieve the instance anywhere and set the properties as you see fit:
var customUISettings = (CustomUISettings)Application.Current.Resources["CustomUISettings"];
customUISettings.HeaderFontSize = 50;
You must make sure that all properties in CustomUISettings class fire the PropertyChanged event. You can see how to implement INotifyPropertyChanged interface for example here.

WPF Style at Windows or App level yields different results

I'm trying to learn Styling in WPF and encountered a funny thing:
There is a difference when I apply a style at application or (main) window level.
When I define the following resource in the App.xaml:
<Application.Resource>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontStyle" Value="Italic" />
</Style>
<Style TargetType="{x:Type GroupBox}">
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Application.Resource>
the GroupBox caption is bold and italic.
When I instead define the styling in the MainWindow.xaml:
<Window.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontStyle" Value="Italic" />
</Style>
<Style TargetType="{x:Type GroupBox}">
<Setter Property="FontWeight" Value="Bold" />
</Style>
</Window.Resources>
The GroupBox caption box is only bold and not italic.
Can anybody explain this behavior?
In picking TextBlock you have unearthed something. TextBlock is not derived from Control, and thus behaves slightly differently.
See https://stackoverflow.com/a/27065140/4258144 :
there is a curious rule in WPF implicit styles are only inherited
across template boundaries by elements which inherit from the Control
class
I guess you can add to that, "unless it is globally specified in App.xaml".
UPDATE:
Following comments, here's a look at a GroupBox visual tree, taken from Snoop.

VS2012: An Error occurred while finding the resource dictionary

I am working on a Windows Phone 8 project, project was created using C# Windows Phone Blank App from templates, I have added a simple ResourceDictionary entitled GPResources.xaml(manually created) and then referenced that file in App.xaml, the file I created is located in the root folder, code below:
<!-- VS2012 saying FontFamily and FontSize properties are not recognized or are not accessable, not sure why... ANYONE?-->
<Style TargetType="{StaticResource GPFontFamily}">
<Setter Property="FontFamily" Value="CalifR.ttf"/>
</Style>
<Style TargetType="{StaticResource GPFontSizeSmall}">
<Setter Property="FontSize" Value="12"/>
</Style>
<Style TargetType="{StaticResource GPFontSizeMedium}">
<Setter Property="FontSize" Value="18"/>
</Style>
<Style TargetType="{StaticResource GPFontSizeLarge}">
<Setter Property="FontSize" Value="22"/>
</Style>
App.Xaml:
<ResourceDictionary x:Key="GPResources">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="GPResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
VS2012 keeps giving me the error: "An Error occurred while finding the resource dictionary" in the App.xaml file, I cannot think of what the problem is, can anyone point me in the right direction?
Cheers
I think you created Resource Dictionary in a wrong way. Following is an example on how to define a style named "GPTextBlock" that will style a TextBlock where it applied, to have a FontSize = 12 and displaying text in Red color.
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="TextBlock" x:Key="GPTextBlock">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="FontSize" Value="12"/>
</Style>
<Style ...>
...
...
</Style>
....
....
</ResourceDictionary>
And overall structure of GPResources.xaml content you had should look like above sample structure. This is one of resources I found explaining about ResourceDictionary you may want to take a look : MSDN Blog

Specify Style from App.Resources to Theme file

Here's a simple thing with which I am struggling with :
I have a style specified in my App.Resources
<Application.Resources>
<Style TargetType="{x:Type igDock:PaneToolWindow}">
<Setter Property="Background" Value="Red"/>
</Style>
</Application.Resources>
I would Like to move this into my theme file by trying something like this.
<SolidColorBrush x:Key="{ComponentResourceKey {x:Type DockManager:PaneToolWindow}, defaultBackground}" Color="Red" PresentationOptions:Freeze="true" />
Of course I am doing something terribly wrong here, My intention is to have all floating windows a default style.
Why use a solid color Brush? The way you had it initially would have worked fine if placed in your custom XAML file.
Just put
<Style TargetType="{x:Type igDock:PaneToolWindow}">
<Setter Property="Background" Value="Red"/>
</Style>
...in your style file.

Categories