0
votes

I have a situation where the wpf application is not able to pickup StaticResource and instead fails with XamlParseException. But if I used a DynamicResource instead, the resource is found and no exception occurs.

I was trying to style and organize wpf resources as recommended at http://projekt202.com/blog/2010/xaml-organization/

I have 2 projects accordingly, a wpf control library that houses all resources and a main wpf project which uses those resources. Here is the structure of the 2 projects

Projects Structure

Wpf_Theme.ControlLibrary
--ResourceDictionaries
----BaseControlStyles
------ButtonStyle.xaml
------TextBoxStyle.xaml
----Brushes
------DefaultBlueTheme
----ResourceLibrary.xaml
Wpf_Theme.Main
--App.xaml
--MainWindow.xaml


Contents of xaml files

ButtonStyle.xaml

<Style TargetType="{x:Type Button}">
    <Setter Property="Background"  Value="{StaticResource ControlBackground}"/>
    <Setter Property="BorderBrush" Value="{StaticResource BorderColor}"/>
    ...
</Style>

DefaultBlueTheme.xaml (Brushes)

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <SolidColorBrush x:Key="PanelBackground" Color="#C8DCF0"/>
    <SolidColorBrush x:Key="BorderColor" Color="#6A8FB5"/>
    <SolidColorBrush x:Key="SelectedItemBackground" Color="Wheat"/>
    <SolidColorBrush x:Key="TextForeground" Color="Black"/>

    <LinearGradientBrush x:Key="ControlBackground" StartPoint="0,0" EndPoint="0,1">
        <LinearGradientBrush.GradientStops>
            <GradientStop Offset="0" Color="#DBECFD"/>
            <GradientStop Offset="0.5" Color="#C7DBEF"/>
            <GradientStop Offset="1" Color="#B0CAE5"/>
        </LinearGradientBrush.GradientStops>
    </LinearGradientBrush>
</ResourceDictionary>

ResourceLibrary.xaml (Merges all dictionaries in one file to be used by main project)

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Brushes/DefaultBlueTheme.xaml"/>
        <ResourceDictionary Source="BaseControlStyles/ButtonStyle.xaml"/>
    </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

App.xaml (In Main project)

<Application x:Class="Wpf_Themes.Main.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="/Wpf_Themes.ControlLibrary;component/ResourceDictionaries/ResourceLibrary.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

MainWindow.xaml

<Window x:Class="Wpf_Themes.Main.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">

    <StackPanel Width="200" Margin="10">
        <Button>Click Me</Button>
    </StackPanel>
</Window>

As stated earlier in the post, I am not able to resolve the style(Background and Border brushes) for the Button using the StaticResource applied in ButtonStyle.xaml. If I use DynamicResource instead, the brushes are found correctly and applied to the Button. Any insights why this behavior occurs.


Edit:
Following Mike's suggestion, I included the xaml files from the Wpf_Theme.ControlLibrary project directly into the App.xaml of the Main project like below

App.xaml

<Application x:Class="Wpf_Themes.Main.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="/Wpf_Themes.ControlLibrary;component/ResourceDictionaries/Brushes/DefaultBlueTheme.xaml"/>
                <ResourceDictionary Source="/Wpf_Themes.ControlLibrary;component/ResourceDictionaries/BaseControlStyles/ButtonStyle.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

and resources are now located correctly using the StaticResource

1
Is there any particular reason why you need to use your ResourceLibrary.xaml file? Could you not just merge all your dictionaries in App.xaml?Mike Eason
Actually I was following the website mentioned earlier. I think its there to avoid the assembly uri syntax for including the xaml. Instead a single file is embedded using the esourceLibrary.xaml. Interestingly, if I avoid the ResourceLibrary.xaml and instead embed all dictionaries directly in App.xaml, it works and resources are properly located. Not sure though why!Jatin

1 Answers

0
votes

Static resource references are resolved at parse time (for the most part), whereas dynamic references are resolved at run time. This means a static reference can only be used if the resource has been parsed before the reference, whereas a dynamic reference can be used as a forward reference for a resource that is defined later.

Source: http://drwpf.com/blog/category/resources/

When the two ResourceDictionaries are in a separte Assembly and you reference them at the same time I would guess that this processing happens at the same time. Whereas if you load them in App.xaml directly it is ensured that they are loaded in the right order.

So the Resources of your first Dictionary are not available to the second Dictionary since you include them in the same Dictionary.

There is two ways to solve the Problem. Either you use DynamicResources which are evalutated at runtime (like you already tried).

Another solution if you now the hyrachie of your Resource Dictionaries you can do several levels. Like:

<Application x:Class="WPF_Theme.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="pack://application:,,,/ControlLibrary;component/ResourceDictionaries/BaseLevel.xaml" />
            <ResourceDictionary Source="pack://application:,,,/ControlLibrary;component/ResourceDictionaries/SecondLevel.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

BaseLevel.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Brushes/DefaultBlueTheme.xaml" />
    </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

SecondLevel.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ResourceDictionary.MergedDictionaries>
          <ResourceDictionary Source="BaseControlStyles/ButtonStyle.xaml" />
    </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

DefaultBlueTheme.xaml and ButtonStyle.xaml stays unchanged.

With this you would ensure that the different ResourceDictionaries are already there if you need them.

I hope that helps.