StaticResource reference inside DataTemplate
Asked Answered
B

1

11

I've been experiencing some strange behaviour when referencing StaticResources from inside a DataTemplate defined in a ResourceDictionary.

In this example, I fill a listbox with the numbers 1 to 9, using a DataTemplate defined in a ResourceDictionary.

Here's the MainWindow.xaml code:

<Window x:Class="testResources.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow"
    Width="525"
    Height="350">
<Grid>
    <ListBox Width="100" ItemTemplate="{StaticResource NumberTemplate}">
        <ListBox.ItemsSource>
            <Int32Collection>1,2,3,4,5,6,7,8,9</Int32Collection>
        </ListBox.ItemsSource>
    </ListBox>
</Grid>

The NumberTemplate is defined in ResourceDictionary1.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DataTemplate x:Key="NumberTemplate">
    <Grid Background="{StaticResource CoolNumbersColor}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="35" />
        </Grid.ColumnDefinitions>
        <TextBox Grid.Column="0" Background="{StaticResource CoolNumbersColor}" Text="{Binding Mode=OneWay}" />
    </Grid>
</DataTemplate>

The StaticResource CoolNumbersColor is defined in App.xaml along with ResourceDictionary1.xaml. Here's my App.xaml file:

<Application x:Class="testResources.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>
        <SolidColorBrush x:Key="CoolNumbersColor">GreenYellow</SolidColorBrush>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/ResourceDictionary1.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

First of all I can see the expected behaviour in Visual Studio 2010 designer. Indeed a colored list of numbers appears. But when trying to run this sample I receive the error

"Cannot find resource named 'CoolNumbersColor'. Resource names are case sensitive"

I can't understand why this happens. Is CoolNumbersColor evaluation deferred somehow? Lexically, it is in front of the merged resourcedictionary.

The only way to make this work (other than using DynamicResources) is to create a second ResourceDictionary (e.g. ResourceDictionary2.xaml), define CoolNumbersColor there and merge them all in ResourceDictionary.MergedDictionaries like this:

<Application x:Class="testResources.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:,,,/ResourceDictionary2.xaml" />
            <ResourceDictionary Source="pack://application:,,,/ResourceDictionary1.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

Brenner answered 7/3, 2014 at 9:7 Comment(4)
Where are you using this resource? I tried it in small app and works fine at my end.Faiyum
Did you try to define CoolNumbersColor before ResourceDictionary.MergedDictionaries in Application.Resources ?Brenner
Yes I did and use it inside DataTemplate of ListBox. Still no issues. Can you try in small app? I suspect problem lies somewhere else.Faiyum
Define the DataTemplate on a separate ResourceDictionary. This way it doesn't work for me.Brenner
P
7

I guess this is due to the fact that a:

StaticResource

  • Does not support forward references
  • It is set only once when the program starts: load-time lookup of resources

DynamicResource

  • Supports forward references
  • Applies for each access to the resource: run-time lookup

Example of forward reference

Not work with StaticResource:

<Window x:Class="SeveralResourceDictionariesHelp.MainWindow"
        Background="{StaticResource testColor}" ... >

<Window.Resources>
    <SolidColorBrush x:Key="testColor">Red</SolidColorBrush>
</Window.Resources>

Work with DynamicResource:

<Window x:Class="SeveralResourceDictionariesHelp.MainWindow"
        Background="{DynamicResource testColor}" ... >

<Window.Resources>
    <SolidColorBrush x:Key="testColor">Red</SolidColorBrush>
</Window.Resources>

At the time the application is launched, the CoolNumbersColor(StaticResource) not available within the "visibility" of DataTemplate, respectively, it throws an exception, he tries to find it in its scope but can not find it.

When using resource dictionaries they are loaded into the first queue, respectively, in this case would be a single scope of view in which the resource is present.

DynamicResource will not be loaded when the application is launched, it will be loaded during his first request to him and at this stage DataTemplate it "sees" the resource.

The question remains: Why this trick works in the Studio?. Perhaps there is a difference between loading at runtime and in design mode, but I have not found an official confirmation in the documentation or elsewhere.

Plasmodium answered 7/3, 2014 at 11:41 Comment(6)
@Theodore Zographos: Yes it is, I wanted to write it in my answer, but limited himself to one paragraph.Plasmodium
Well, lexically at least, I don't see the forward reference, since CoolNumbersColor is defined BEFORE the MergedDictionaries. When the parser evaluates the DataTemplate, it SHOULD find CoolNumbersColor since it is defined in the lookup chain: 1.same xaml 2.Generic.xaml 3. app.resourcesBrenner
@Theodore Zographos: In WPF, elements looks for resource firstly from its resource section and then bubbles up to the root of the element tree, finally reach the system theme, the following sequence illustrate the order: 1. Element hierarchy. 2. Application.Resources 3. Type theme 4. System theme.Plasmodium
@Theodore Zographos: It looks like a forward reference. When the style is in the local visibility - it must be is static, if not - it is dynamic. I met this statement in the Internet if you want I can give you the source.Plasmodium
+1 for the correct order. However, the CoolNumbersColor IS in the resource chain. It seems that MergedDictionaries are evaluated first and foremost in App.Resources.Brenner
@Theodore Zographos: Yes, it is. Dictionaries that are in App.xaml go in the first order, and all the resources that are available there are global to the application.Plasmodium

© 2022 - 2024 — McMap. All rights reserved.