Ссылка на StaticResource внутри DataTemplate

У меня возникло странное поведение при обращении к StaticResources изнутри DataTemplate, определенного в ResourceDictionary.

В этом примере я заполняю список числами от 1 до 9, используя DataTemplate, определенный в ResourceDictionary.

Вот код MainWindow.xaml:

<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

«Не удается найти ресурс с именем 'CoolNumbersColor'. Имена ресурсов чувствительны к регистру»

Я не могу понять, почему это происходит. CoolNumbersColor оценка как-то откладывается? Лексически он находится перед объединенным ресурсным словарем.

Единственный способ выполнить эту работу (кроме использования DynamicResources) - создать второй ResourceDictionary (например, ResourceDictionary2.xaml), определить там CoolNumbersColor и объединить их все в ResourceDictionary.MergedDictionaries следующим образом:

<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>


person Theodore Zographos    schedule 07.03.2014    source источник
comment
Где вы используете этот ресурс? Я попробовал это в небольшом приложении и отлично работает с моей стороны.   -  person Rohit Vats    schedule 07.03.2014
comment
Вы пытались определить CoolNumbersColor до ResourceDictionary.MergedDictionaries в Application.Resources?   -  person Theodore Zographos    schedule 07.03.2014
comment
Да, я использовал его внутри DataTemplate из ListBox. По-прежнему нет проблем. Можете попробовать в небольшом приложении? Я подозреваю, что проблема в другом.   -  person Rohit Vats    schedule 07.03.2014
comment
Определите DataTemplate в отдельном ResourceDictionary. У меня это не работает.   -  person Theodore Zographos    schedule 07.03.2014


Ответы (1)


Думаю, это связано с тем, что:

StaticResource

  • Не поддерживает прямые ссылки
  • Устанавливается только один раз при запуске программы: время загрузки поиск ресурсов

DynamicResource

  • Поддерживает прямые ссылки
  • Применяется для каждого доступа к ресурсу: поиск во время выполнения

Example of forward reference

Не работает с StaticResource:

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

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

Работа с DynamicResource:

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

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

В момент запуска приложения CoolNumbersColor (StaticResource) недоступен в пределах «видимости» DataTemplate, соответственно, он выдает исключение, он пытается найти его в своей области, но не может его найти .

При использовании словарей ресурсов они загружаются в первую очередь, соответственно, в этом случае будет одна область просмотра, в которой присутствует ресурс.

DynamicResource не будет загружаться при запуске приложения, оно будет загружено во время его первого запроса к нему и на этом этапе DataTemplate оно "видит" ресурс.

Остается вопрос: Why this trick works in the Studio?. Возможно, есть разница между загрузкой во время выполнения и в режиме разработки, но я не нашел официального подтверждения ни в документации, ни где-либо еще.

person Anatoliy Nikolaev    schedule 07.03.2014
comment
@ Теодор Зографос: Да, я хотел написать это в своем ответе, но ограничился одним абзацем. - person Anatoliy Nikolaev; 07.03.2014
comment
Ну, по крайней мере лексически, я не вижу прямой ссылки, поскольку CoolNumbersColor определен ДО MergedDictionaries. Когда синтаксический анализатор оценивает DataTemplate, он ДОЛЖЕН найти CoolNumbersColor, поскольку он определен в цепочке поиска: 1. тот же xaml 2. Generic.xaml 3. app.resources - person Theodore Zographos; 07.03.2014
comment
@Theodore Zographos: В WPF элементы сначала ищут ресурс в своем разделе ресурсов, а затем всплывают до корня дерева элементов, наконец, достигают системной темы. Порядок иллюстрируется следующей последовательностью: 1. Иерархия элементов. 2. Приложение. Ресурсы 3. Типовая тема 4. Системная тема. - person Anatoliy Nikolaev; 07.03.2014
comment
@ Теодор Зографос: Это похоже на прямую ссылку. Когда стиль находится в локальной видимости - он должен быть статическим, если нет - динамическим. Я встречал это заявление в Интернете, если хотите, могу дать вам источник. - person Anatoliy Nikolaev; 07.03.2014
comment
+1 за правильный порядок. Однако CoolNumbersColor IS в цепочке ресурсов. Кажется, что MergedDictionaries оцениваются в первую очередь в App.Resources. - person Theodore Zographos; 07.03.2014
comment
@ Теодор Зографос: Да, это так. Словари в App.xaml идут в первом порядке, и все доступные там ресурсы являются глобальными для приложения. - person Anatoliy Nikolaev; 07.03.2014