Search code examples
wpfresourcedictionarystaticresource

WPF Resource dictionary lookup rules


I have two resource files (resource dictionaries)

  • Brushes.xaml : contains some brushes
  • Templates.xaml : contains some templates that statically reference (StaticResource) the keys in Brushes.xaml

If in my main window, I do :

<Grid>
    <Grid.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Brushes.xaml" />
                <ResourceDictionary Source="Templates.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Grid.Resources>
    <StackPanel>
        <ContentControl ContentTemplate="{StaticResource TemplateA}"
                        Height="25" />
        <ContentControl ContentTemplate="{StaticResource TemplateB}"
                        Height="25" />
    </StackPanel>

</Grid>

It fails to find the brushes when generating the templates.

If I move the resource loading into App.xaml, it works.

Why are the resource lookup rules different in the two situations?

I was also quite surprised to see that the following fails as well?

 <Window.Resources>
     <SolidColorBrush x:Key="BrushA">Red</SolidColorBrush>
     <SolidColorBrush x:Key="BrushB">Green</SolidColorBrush>
 </Window.Resources>

 <Grid>
     <Grid.Resources>
         <ResourceDictionary>
             <ResourceDictionary.MergedDictionaries>
                 <ResourceDictionary Source="Templates.xaml" />
             </ResourceDictionary.MergedDictionaries>
         </ResourceDictionary>
     </Grid.Resources>
     <StackPanel>
         <ContentControl ContentTemplate="{StaticResource TemplateA}"
                         Height="25" />
         <ContentControl ContentTemplate="{StaticResource TemplateB}"
                         Height="25" />
     </StackPanel>

 </Grid>

Grid is a child of the Window, so why can't the brushes be found when it walks up the tree?

The only information I can find on lookup rules is the following, but I'm not sure it answers my question https://learn.microsoft.com/en-us/dotnet/desktop/wpf/systems/xaml-resources-merged-dictionaries?view=netdesktop-8.0

EDIT :

It also appears that the rules change depending on how you define the resources.

In the code below, I've defined the resources in what I would think to be the same way. Its just that one version uses Source to keep the code cleaner, and the other version defines them in line.

Yet only the commented out version works.

<Grid>
    <Grid.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Brushes.xaml" />
                <ResourceDictionary Source="Templates.xaml" />
            </ResourceDictionary.MergedDictionaries>

            <!--<ResourceDictionary.MergedDictionaries>
                <ResourceDictionary>
                    <SolidColorBrush x:Key="BrushA">Red</SolidColorBrush>
                    <SolidColorBrush x:Key="BrushB">Green</SolidColorBrush>
                </ResourceDictionary>
                <ResourceDictionary>
                    <DataTemplate x:Key="TemplateA">
                        <Grid Background="{StaticResource BrushA}" />
                    </DataTemplate>
                    <DataTemplate x:Key="TemplateB">
                        <Grid Background="{StaticResource BrushB}" />
                    </DataTemplate>
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>-->
        </ResourceDictionary>
    </Grid.Resources>
    <StackPanel>
        <ContentControl ContentTemplate="{StaticResource TemplateA}"
                        Height="25" />
        <ContentControl ContentTemplate="{StaticResource TemplateB}"
                        Height="25" />
    </StackPanel>

</Grid>

Solution

  • AFAIU, the lookup from a resource (resource A) to other resource (resource B) is done not at where the resource A is used but at where the resource A is defined and the reference is made. So, it depends on whether the resource in Brushes.xaml (resource B) can be accessed from the resource in Templates.xaml (resource A).

    In the case of Grid.Resources, a resource in Brushes.xaml can be accessed from the resources/elements only in the scope of the Grid and Templates.xaml is NOT in it. The same applies to Window.Resources. In contrast, in the case of Application.Resources, a resource in Brushes.xaml can be accessed from the whole application including Templates.xaml.

    EDIT

    If you define a resource inline in Grid.Resources, they will be in the scope of the Grid and thus will be able to access the resources in Brushes.xaml. The lookup rule is the same.