Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

StaticResource reference inside DataTemplate

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>

like image 441
Theodore Zographos Avatar asked Mar 07 '14 09:03

Theodore Zographos


1 Answers

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.

like image 195
Anatoliy Nikolaev Avatar answered Sep 28 '22 05:09

Anatoliy Nikolaev