Using style defined in merged dictionary from another merged dictionary - c#

Below you can see how I am trying to segregate styles by merging dictionaries (I'm skipping namespaces for the sake of cleanliness)
App.xaml:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Style/Colors.xaml" />
<ResourceDictionary Source="Style/HeaderStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Colors.xaml:
<SolidColorBrush x:Key="DarkTextForeground" Color="#7471b9"/>
HeaderStyle.xaml:
<Style x:Key="HeaderTextBlockStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource DarkTextForeground}"/>
<Setter Property="FontWeight" Value="Black"/>
</Style>
During compilation I get a following error:
Cannot find a Resource with the Name/Key DarkTextForeground
To make It work we have to merge Colors.xaml inside HeaderStyle.xaml like this:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Colors.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style x:Key="HeaderTextBlockStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource DarkTextForeground}"/>
<Setter Property="FontWeight" Value="Black"/>
</Style>
Can anyone explain to me, why I have to reference Colors.xaml in HeaderStyle.xaml? Can't I just reference styles defined in different merged dictionary?I assume that Colors.xaml is loaded before HeaderStyle.xaml so it should be visible for dictionaries defined later.

This is a response to my question from Erick Fleck at msdn forums:
In your first example each file is parsed independently and then added to the merged dictionary so they don't know anything about each other...similarly, the XAML in a merged dictionary cannot reference names in the 'parent' ResourceDictionary. In other words, you should think of a MergedDictionaries as a one-way reference.
It's the way It works I guess...

Related

Setup for ResourceDictionary [duplicate]

I have resource dictionary files (MenuTemplate.xaml, ButtonTemplate.xaml, etc) that I want to use in multiple separate applications. I could add them to the applications' assemblies, but it's better if I compile these resources in one single assembly and have my applications reference it, right?
After the resource assembly is built, how can I reference it in the App.xaml of my applications? Currently I use ResourceDictionary.MergedDictionaries to merge the individual dictionary files. If I have them in an assembly, how can I reference them in xaml?
Check out the pack URI syntax. You want something like this:
<ResourceDictionary Source="pack://application:,,,/YourAssembly;component/Subfolder/YourResourceFile.xaml"/>
An example, just to make this a 15 seconds answer -
Say you have "styles.xaml" in a WPF library named "common" and you want to use it from your main application project:
Add a reference from the main project to "common" project
Your app.xaml should contain:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Common;component/styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
I'm working with .NET 4.5 and couldn't get this working... I was using WPF Custom Control Library. This worked for me in the end...
<ResourceDictionary Source="/MyAssembly;component/mytheme.xaml" />
source: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/11a42336-8d87-4656-91a3-275413d3cc19
Resource-Only DLL is an option for you. But it is not required necessarily unless you want to modify resources without recompiling applications. Have just one common ResourceDictionary file is also an option. It depends how often you change resources and etc.
<ResourceDictionary Source="pack://application:,,,/
<MyAssembly>;component/<FolderStructureInAssembly>/<ResourceFile.xaml>"/>
MyAssembly - Just assembly name without extension
FolderStructureInAssembly - If your resources are in a folde, specify folder structure
When you are doing this it's better to aware of siteOfOrigin as well.
WPF supports two authorities: application:/// and siteoforigin:///.
The application:/// authority identifies application data files that
are known at compile time, including resource and content files. The
siteoforigin:/// authority identifies site of origin files. The scope
of each authority is shown in the following figure.
For UWP:
<ResourceDictionary Source="ms-appx:///##Namespace.External.Assembly##/##FOLDER##/##FILE##.xaml" />
Using XAML:
If you know the other assembly structure and want the resources in c# code, then use below code:
ResourceDictionary dictionary = new ResourceDictionary();
dictionary.Source = new Uri("pack://application:,,,/WpfControlLibrary1;Component/RD1.xaml", UriKind.Absolute);
foreach (var item in dictionary.Values)
{
//operations
}
Output: If we want to use ResourceDictionary RD1.xaml of Project WpfControlLibrary1 into StackOverflowApp project.
Structure of Projects:
Resource Dictionary:
Code Output:
PS: All ResourceDictionary Files should have Build Action as 'Resource' or 'Page'.
Using C#:
If anyone wants the solution in purely c# code then see my this
solution.
I know I will probably go to WPF hell but I like to keep it simple.
In my "external" WPF project named MyCorp.Wpf.Dll where I have a folder called assets with my resource dictionaries
MyCorp.Wpf.Dll
|- Assets
|- TextStyles.xaml
|- Colours.axml
Let's assume I have this TextStyles.xaml with the UI font styles that I need to apply because I need windows 10/ 11 style compliance
<Style x:Key="Header" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Sego UI Light"/>
<Setter Property="FontSize" Value="46" />
</Style>
<Style x:Key="Subheader" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Sego UI Light"/>
<Setter Property="FontSize" Value="32" />
</Style>
<Style x:Key="Title" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Sego UI SemiLight"/>
<Setter Property="FontSize" Value="24" />
</Style>
<Style x:Key="SubTitle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Sego UI Normal"/>
<Setter Property="FontSize" Value="20" />
</Style>
<Style x:Key="Base" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Sego Semibold"/>
<Setter Property="FontSize" Value="15" />
</Style>
<Style x:Key="Body" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Sego Normal"/>
<Setter Property="FontSize" Value="15" />
</Style>
<Style x:Key="Caption" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Sego Normal"/>
<Setter Property="FontSize" Value="12" />
</Style>
</ResourceDictionary>
These styles are in my corporate style guide and I am re-sing them al over the place
now in my brand new application I can use the corporate style DLL from an internal NuGet package feed or I link it because It happens to be in my solution using the following resource dictionary
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyCorp.Wpf;component/Assets/TextStyles.xaml"/>
<ResourceDictionary Source="/MyCorp.Wpf;component/Assets/Styles.xaml"/>
<ResourceDictionary Source="/MyCorp.Wpf;component/Assets/Brushes.xaml"/>
<ResourceDictionary Source="/MyCorp.Wpf;component/Assets/ColorStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
I have no clue where the extra component come from, I just know I needed. then in my new application I just link it like so:
<Application x:Class="MyNew.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ExternalResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
<BooleanToVisibilityConverter x:Key="VisibilityConverter"/>
</ResourceDictionary>
</Application.Resources>
</Application>
This way I have all external links in the ExternalResources.xaml where everyone understands where they came from and updating them is easy
I can then use the external resource definitions like any other in my windows, page and controls
<syncfusion:ChromelessWindow x:Class="IDPS.ChromelessWindow1"
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:IDPS"
xmlns:r="clr-namespace:IDPS.Wpf.Properties;assembly=IDPS.Wpf"
xmlns:syncfusion="http://schemas.syncfusion.com/wpf"
syncfusion:SfSkinManager.Theme="{syncfusion:SkinManagerExtension ThemeName=FluentDark}"
mc:Ignorable="d"
MinHeight="450" MinWidth="800">
<Grid>
<TextBlock Text="Hello world" Style="{StaticResource Title}"/>
</Grid>
</syncfusion:ChromelessWindow>

VS2012 The resource "X" could not be resolved

I have a Resources.xaml file in my project that contains a resource dictionary like so:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="GPHeaderFontSize" TargetType="TextBlock">
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="FontSize" Value="24" />
<Setter Property="Text" Value="BLAHHHHH"/>
</Style>
</ResourceDictionary>
I have included this dictionary in App.xaml like so:
<Application x:Class="GoldenPlains.App"
xmlns="schemas.microsoft.com/winfx/2006/xaml/presentation";
xmlns:x="schemas.microsoft.com/winfx/2006/xaml";
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone">
<Application.Resources>
<local:LocalizedStrings xmlns:local="clr-namespace:GoldenPlains" x:Key="LocalizedStrings"/>
<ResourceDictionary x:Key="GPResources">
<ResourceDictionary.MergedDictionaries>
<!-- Sometimes VS2012 complaining about path with blue line, please ignore it as path is correct -->
<ResourceDictionary Source="Styles/GPResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style x:Key="GPRootOverlayBarStyle" TargetType="Image">
<Setter Property="Source" Value="Assets/Images/root_brown_horizontal_bar.png"/>
<Setter Property="Width" Value="729"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Stretch" Value="Uniform"/>
</style>
</Application.Resources>
...
...
</Application>
However when I try to reference an element in the resource dictionary from another Page.xaml file it cannot seem to resolve the resource....
eg:
I have tried using a binding like so:
<TextBlock Style="{Binding Path=LocalizedResources.MyTextBlockStyle, Source= {StaticResource GPResources}}"/>
it does not indicate that something is wrong but nothing shows up on the UI.
A point in the right direction would be great, cheers.
Resource Dictionary definition in the App.xaml should be about like following example :
<Application.Resources>
<ResourceDictionary>
<local:LocalizedStrings xmlns:local="clr-namespace:GoldenPlains" x:Key="LocalizedStrings"/>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/GPResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!-- Other resources if you have -->
</ResourceDictionary>
</Application.Resources>
Then, when you need to apply style defined in Resources.xaml to a UI control, simply refer to the style's key/name :
<TextBlock Style="{StaticResource GPHeaderFontSize}" />
Notes: All resources need to be inside ResourceDictionary tag, including LocalizedStrings.

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

Style inheritance based on different XAML

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.

WPF - Mixing style defined in dictionary with style defined in parent control

I define a custom look for Button control in a resource dictionary:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="Button" x:Key="BaseButtonStyle">
<Setter Property="Background" Value="Blue"/>
</Style>
</ResourceDictionary>
Then I try to change the style of the window where the buttons are located.
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary.xaml"/>
<ResourceDictionary>
<Style TargetType="Button" BasedOn="{StaticResource BaseButtonStyle}">
<Setter Property="Foreground" Value="Red"/>
</Style>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
I have what I expected in WPF designer: a blue button with red text.
But in run-time, both styles are not applied and the button has default colors.
How can I fix this?
The one below works. I just moved the Style out of the MergedDictionaries and placed it on the outer ResourceDictionary.
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="Button" BasedOn="{StaticResource BaseButtonStyle}">
<Setter Property="Foreground" Value="Red"/>
</Style>
</ResourceDictionary>
</Window.Resources>
In your original XAML, I'm not sure why the designer was able to render it correctly while the WPF runtime didn't. The MSDN documentation says though that:
A merged ResourceDictionary does not have resource elements defined within it in markup. Instead, the merged dictionary is a ResourceDictionary with no markup child elements defined (or with no elements added through code), but with a URI specified for Source.
It might have something to do with it.

Categories