Why does this XAML merged resource configuration fail at runtime? - c#

I have the following App.xaml:
<Application
x:Class="Genisyss.V2.Client.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Genisyss.V2.Client"
ShutdownMode="OnExplicitShutdown">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="Resources/ShellResources.xaml" />
<ResourceDictionary>
<local:AppBootstrapper
x:Key="bootstrapper" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
ShellResources.xaml looks like this:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
x:Class="Genisyss.V2.Client.Resources.ShellResources"
x:ClassModifier="public">
<ResourceDictionary.MergedDictionaries>
<!-- EXTERNAL RESOURCES -->
<ResourceDictionary
Source="/Teton.Wpf;component/Themes/Generic.xaml" />
<ResourceDictionary
Source="Images.xaml" />
</ResourceDictionary.MergedDictionaries>
<!-- controls and templates defined, etc -->
</ResourceDictionary>
Configured this way, the program fails at runtime with "resource not found" or "xaml parse exception".
If I change App.xaml to ALSO include external resources, like this:
<Application
x:Class="Genisyss.V2.Client.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Genisyss.V2.Client"
ShutdownMode="OnExplicitShutdown">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- NOTE ADDITION OF EXTERNAL RESOURCES -->
<ResourceDictionary
Source="/Teton.Wpf;component/Themes/Generic.xaml" />
<ResourceDictionary
Source="Resources/ShellResources.xaml" />
<ResourceDictionary>
<local:AppBootstrapper
x:Key="bootstrapper" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Now my program finds the resources at runtime and runs without error. What gives with this? I thought the point of merged resources was ACTUALLY TO MERGE THE RESOURCES, so that you didn't need to declare them in two places.
EDIT
Changed the Source property in ShellResources.xaml to be an absolute pack uri:
pack://application:,,,/Teton.Wpf;component/Themes/Generic.xaml
But this made no difference.

This bug showed up because of the order that things need to be defined in a resource file. I have a WPF controls project that defines some custom controls AND overrides the default styles of several built-in controls.
To make a long story short, I had resources that were defined further down in the Generic.xaml file, and they were being accessed further up - that's a no-no. Resources are apparently parsed only once, in a strict top-down fashion. I was under the impression that they were parsed in a two-or-more pass manner just like normal c# source code.
To avoid this happening, here is a suggested way to lay out your Generic.xaml in a WPF Controls project:
<!-- Shared resources like brushes and colors -->
<!-- DEFAULT control styles, e.g. <Style TargetType="{x:Type TextBox}"... -->
<!-- Control styles for custom controls that are defined in your project -->
Thanks to #Aybe for pushing me to dig deeper on this.

Related

Window style from an external (dll) resource dictionary doesn't apply in design mode

I have create a external control library which hosts some resource dictionaries etc. My problem is when I try to apply a style on a window element. Style's changes become visible only in running mode!!!
An example of the resource dictionary from my control library:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="Window_Style" TargetType="Window">
<Setter Property="Background" Value="#FF272727"/>
</Style>
</ResourceDictionary>
This is how I include my external resource dictionary into my app:
<Application x:Class="SigmaLibMaster.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SigmaLibMaster"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/SigmaLib;component/Resources/Styles/Window.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
And how I apply it to my window element:
<Window x:Class="SigmaLibMaster.MainWindow"
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:SigmaLibMaster"
mc:Ignorable="d"
Title="MainWindow" Height="480" Width="840"
Style="{DynamicResource Window_Style}">
<Grid >
</Grid>
</Window>
Any idea why is this happening?
PS: Please keep in mind that I recently switched from WinForms to WPF!!! :)
You can sometimes find that resources from libraries don't work at design time.
It's a bug IMO.
The work round I use is design time resources.
This is a mechanism which was originally intended for blend. But the wpf designer in visual studio is the same designer as blend now.
I have a library called uilib.
In the properties of that I add a resource dictionary called DesignTimeResources.xaml. It must be that name.
In the csproj I have the following:
<ItemGroup>
<Page Include="Properties\DesignTimeResources.xaml" Condition="'$(DesignTime)'=='true' OR ('$(SolutionPath)'!='' AND Exists('$(SolutionPath)') AND '$(BuildingInsideVisualStudio)'!='true' AND '$(BuildingInsideExpressionBlend)'!='true')">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
<ContainsDesignTimeResources>true</ContainsDesignTimeResources>
</Page>
Note particularly that ContainsDesignTimeResources tag.
That merges a bunch of resource dictionaries I have in uilib:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:UILib">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/UILib;component/Resources/Geometries.xaml"/>
<ResourceDictionary Source="pack://application:,,,/UILib;component/Resources/ControlTemplates.xaml"/>
<ResourceDictionary Source="pack://application:,,,/UILib;component/Resources/FontResources.xaml"/>
<ResourceDictionary Source="pack://application:,,,/UILib;component/Resources/UILibResources.xaml"/>
<ResourceDictionary Source="pack://application:,,,/UILib;component/Resources/HypsoColoursRD.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
It will not merge these resources in an extra time when you build. The conditions in the tags mean it's design time only.
You can probably find a bunch more on this by searching now you know it exists.
https://dennymichael.net/2016/07/28/wpf-design-time-resources-dictionary/

Where to add ObjectDataProvider in Application.Resources with ResourceDictionary

I followed this Tutorial and got stuck on the Create Instance of Config Settings Class-part. Here they just add the ObjectDataProvider in the Application.Resources. In my case there is already a ResourceDictionary in this context and I think this causes the problem.
My App.xaml:
<Application x:Class="MyApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:config="clr-namespace:MyApp.ViewModels"
StartupUri="MainWindow.xaml">
<Application.Resources>
<!-- create instance of config-settings class -->
<ObjectDataProvider x:Key="AppSettingsDataProvider" ObjectType="{x:Type config:AppSettingsManager}"/>
<ResourceDictionary x:Key="MainDictionary">
<!-- also not working: -->
<!--<ObjectDataProvider x:Key="AppSettingsDataProvider" ObjectType="{x:Type config:AppSettingsManager}"/>-->
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Folder/file1.xaml" />
<ResourceDictionary Source="pack://application:,,,/Folder/file2.xaml" />
<!-- <ResourceDictionary Source="{Binding Source={StaticResource AppSettingsDataProvider}, Path=LoadMethod, Mode=OneWay}"/>-->
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
When I run the program my ResourceDictionary is not loaded anymore (Application.Current.Ressources.MergedDictionaries is empty), without the ObjectDataProvider everything works fine. Putting the ObjectDataProvider in the ResourceDictionary like suggested in the post Problems adding an ObjectDataProvider in resources did not help (is it different in the Application-class?). So where to put the ObjectDataProvider?

WPF window and controls style

I have defined in my WPF application all the styles that I want to apply. The problem is that if I open an other window it doesn't have the same style of the main window because it is defined in an other project.
How can I apply the styles of the main application?
Thank you!
EDIT
This is a part of my App.xaml
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Assets/Styles/Themes/Dark.xaml" />
<ResourceDictionary Source="Assets/Styles/Border.xaml" />
<ResourceDictionary Source="Assets/Styles/BaseBlock.xaml" />
<ResourceDictionary Source="Assets/Styles/Buttons.xaml" />
.....
What I need is to apply the styles defined in the Main Project to the ones defined in Project1 in order to have uniformity.
Put your styles to the ResourceDictionary of your application resources in App.xaml. So you can use your resources everywhere via {StaticResource keyOfYourStyle}. If you want, that your styles be applied to all controls of the type, then use default styles:
<Style TargetType="Border" BasedOn="{StaticResource keyOfYourStyle}>
<Application.Resources>
<ResourceDictionary>
<ThisResourceWillBeAccessedEveryWhere x:Key="ResName"/>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/YourAssembley;component/Resources/ButtonStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>

Cannot deploy app with style in app.xaml

I have following app.xaml:
<Application>
...
<Application.Resources>
<!-- Application-specific resources -->
<ResourceDictionary>
<viewModels:ViewModelLocator x:Key="ViewModelLocator"></viewModels:ViewModelLocator>
<ResourceDictionary.MergedDictionaries>
<!--
Styles that define common aspects of the platform look and feel
Required by Visual Studio project and item templates
-->
<ResourceDictionary Source="/Styles/Styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style x:Key="PivotStylePassStore" TargetType="Pivot">
...
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
It builds fine, but cannot it deploy - there is error:
xaml Duplication assignment to the 'Items' property of the
'ResourceDictionary' object
When style entry is removed - there is no problem. What is going on?
Place all your custom/local styles/resources below the MergedDictionaries.
<Application>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!--
Styles that define common aspects of the platform look and feel
Required by Visual Studio project and item templates
-->
<ResourceDictionary Source="/Styles/Styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!-- Application-specific resources -->
<viewModels:ViewModelLocator x:Key="ViewModelLocator"></viewModels:ViewModelLocator>
<Style x:Key="PivotStylePassStore" TargetType="Pivot">
...
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
Actually it shouldn't make a difference if they are all above or below, but they have to be together. Application.Resources is a property of Application, everything else is basically the "default" property of the Application XAML Element (kind of like Text for TextBoxes or Content for various others). You can't mix them together.

Can i store string in <Application.Resources> and bind to it?

I'm using Microsoft's AdControl on several pages... but in order to simplify it i would like to store ApplicationId once and read it as a resource.
Could it be possible to use in the App.xaml and then in the control set the binding to it? But how?
Use "{StaticResource name}" just like you would with <Page.Resources>
To store the resource, create a new <ResourceDictionary> in <ResourceDictionary.MergedDictionaries> and place your resource in that.
For example:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!--
Styles that define common aspects of the platform look and feel
Required by Visual Studio project and item templates
-->
<ResourceDictionary Source="Common/StandardStyles.xaml"/>
<ResourceDictionary>
<x:String x:Key="Foo">Bar</x:String>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>

Categories

Resources