Поделиться через


Ссылки на ресурсы ResourceDictionary и XAML

Вы можете определить пользовательский интерфейс или ресурсы для приложения с помощью XAML. Ресурсы обычно являются определениями некоторых объектов, которые вы ожидаете использовать несколько раз. Чтобы получить ссылку на ресурс XAML позже, укажите ключ для ресурса, который действует как его имя. Вы можете ссылаться на ресурс в приложении или на любой странице XAML. Ресурсы можно определить с помощью элемента ResourceDictionary из XAML среды выполнения Windows. Затем можно ссылаться на ресурсы с помощью расширения разметки StaticResource или расширения разметки ThemeResource.

Элементы XAML, которые вы можете часто хотеть объявлять в качестве ресурсов XAML, включают Style, ControlTemplate, компоненты анимации и подклассы Brush. Здесь мы объясним, как определить ресурсы ResourceDictionary и ключи, а также как ресурсы XAML связаны с другими ресурсами, которые определяются как часть приложения или пакета приложения. Мы также объясняем расширенные функции словаря ресурсов, такие как MergedDictionaries и ThemeDictionaries.

Предпосылки

Твердое понимание разметки XAML. Мы рекомендуем ознакомиться с обзором XAML.

Определение и использование ресурсов XAML

Ресурсы XAML — это объекты, которые используются в разметке более одного раза. Ресурсы определяются в ResourceDictionary, как правило, в отдельном файле или в верхней части страницы разметки, как показано ниже.

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <x:String x:Key="greeting">Hello world</x:String>
        <x:String x:Key="goodbye">Goodbye world</x:String>
    </Page.Resources>

    <TextBlock Text="{StaticResource greeting}" Foreground="Gray" VerticalAlignment="Center"/>
</Page>

В этом примере:

  • <Page.Resources>…</Page.Resources> — определяет словарь ресурсов.
  • <x:String> — определяет ресурс с ключом "приветствие".
  • {StaticResource greeting}. Поиск ресурса с ключом "приветствие", который назначается свойству TextTextBlock.

Примечание НЕ путайте понятия, связанные с ResourceDictionary, с параметром сборки Resource, файлами ресурсов (.resw) или другими "ресурсами", которые обсуждаются в контексте структуры проекта кода, ответственного за создание вашего пакета приложения.

Ресурсы не должны быть строками; они могут быть любым общим объектом, такими как стили, шаблоны, кисти и цвета. Однако элементы управления, фигуры и другие FrameworkElement не могут быть использованы совместно, поэтому они не могут быть объявлены в качестве повторно используемых ресурсов. Дополнительные сведения о совместном использовании см. в разделе «Ресурсы XAML должны быть доступными для совместного использования» далее в этом разделе.

Здесь как кисть, так и строка объявляются как ресурсы и используются элементами управления на странице.

<Page
    x:Class="SpiderMSDN.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <SolidColorBrush x:Key="myFavoriteColor" Color="green"/>
        <x:String x:Key="greeting">Hello world</x:String>
    </Page.Resources>

    <TextBlock Foreground="{StaticResource myFavoriteColor}" Text="{StaticResource greeting}" VerticalAlignment="Top"/>
    <Button Foreground="{StaticResource myFavoriteColor}" Content="{StaticResource greeting}" VerticalAlignment="Center"/>
</Page>

Все ресурсы должны иметь ключ. Обычно этот ключ является строкой, определенной символом x:Key="myString". Однако существует несколько других способов указать ключ:

  • стиле и ControlTemplate требуют TargetTypeи будут использовать TargetType в качестве ключа, если x:Key не указан. В этом случае ключ является фактическим объектом Type, а не строкой. (См. примеры ниже)
  • ресурсы DataTemplate с TargetType будут использовать TargetType в качестве ключа, если x:Key не указан. В этом случае ключ является фактическим объектом Type, а не строкой.
  • x:Name можно использовать вместо x:Key. Однако x:Name также создает код за полем для ресурса. В результате x:Name является менее эффективным, чем x:Key, так как это поле необходимо инициализировать при загрузке страницы.

Расширение разметки staticResource может извлекать ресурсы только со строковым именем (x:Key или x:Name). Однако платформа XAML также ищет неявные ресурсы стиля (те, которые используют TargetType , а не x:Key или x:Name), когда он решает, какой стиль и шаблон использовать для элемента управления, который не задает свойства Style и ContentTemplate или ItemTemplate .

Здесь стиль имеет неявный ключ типаtypeof(Button), и поскольку кнопка в нижней части страницы не указывает свойство стиля , она ищет стиль с ключом типаtypeof(Button):

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <Style TargetType="Button">
            <Setter Property="Background" Value="Red"/>
        </Style>
    </Page.Resources>
    <Grid>
       <!-- This button will have a red background. -->
       <Button Content="Button" Height="100" VerticalAlignment="Center" Width="100"/>
    </Grid>
</Page>

Дополнительные сведения о неявных стилях и их работе см. в стилях элементов управления и шаблонах управления.

Поиск ресурсов в коде

Доступ к элементам словаря ресурсов осуществляется так же, как и к любому другому словарю.

Предупреждение

При выполнении поиска ресурсов в коде рассматриваются только ресурсы в Page.Resources словаре. В отличие от расширения разметки staticResource, код не возвращается в словарь , если ресурсы не найдены в первом словаре.

 

В этом примере показано, как получить redButtonStyle ресурс из словаря ресурсов страницы:

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <Style TargetType="Button" x:Key="redButtonStyle">
            <Setter Property="Background" Value="red"/>
        </Style>
    </Page.Resources>
</Page>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            Style redButtonStyle = (Style)this.Resources["redButtonStyle"];
        }
    }
    MainPage::MainPage()
    {
        InitializeComponent();
        Windows::UI::Xaml::Style style = Resources().TryLookup(winrt::box_value(L"redButtonStyle")).as<Windows::UI::Xaml::Style>();
    }

Чтобы найти ресурсы по всему приложению из кода, используйте Application.Current.Resources для получения словаря ресурсов приложения, как показано здесь.

<Application
    x:Class="MSDNSample.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:SpiderMSDN">
    <Application.Resources>
        <Style TargetType="Button" x:Key="appButtonStyle">
            <Setter Property="Background" Value="red"/>
        </Style>
    </Application.Resources>

</Application>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            Style appButtonStyle = (Style)Application.Current.Resources["appButtonStyle"];
        }
    }
    MainPage::MainPage()
    {
        InitializeComponent();
        Windows::UI::Xaml::Style style = Application::Current().Resources()
                                                               .TryLookup(winrt::box_value(L"appButtonStyle"))
                                                               .as<Windows::UI::Xaml::Style>();
    }

Вы также можете добавить ресурс приложения в код.

При этом следует помнить о двух вещах.

  • Сначала необходимо добавить ресурсы, прежде чем любая страница попытается использовать ресурс.
  • Во-вторых, нельзя добавлять ресурсы в конструктор приложения.

При добавлении ресурса в метод Application.OnLaunched можно избежать обеих проблем.

// App.xaml.cs
    
sealed partial class App : Application
{
    protected override void OnLaunched(LaunchActivatedEventArgs e)
    {
        Frame rootFrame = Window.Current.Content as Frame;
        if (rootFrame == null)
        {
            SolidColorBrush brush = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 0, 255, 0)); // green
            this.Resources["brush"] = brush;
            // … Other code that VS generates for you …
        }
    }
}
// App.cpp

void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
    Frame rootFrame{ nullptr };
    auto content = Window::Current().Content();
    if (content)
    {
        rootFrame = content.try_as<Frame>();
    }

    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (rootFrame == nullptr)
    {
        Windows::UI::Xaml::Media::SolidColorBrush brush{ Windows::UI::ColorHelper::FromArgb(255, 0, 255, 0) };
        Resources().Insert(winrt::box_value(L"brush"), winrt::box_value(brush));
        // … Other code that VS generates for you …

Каждый FrameworkElement может иметь словарь ресурсов.

FrameworkElement является базовым классом, от которого наследуют другие классы, и имеет свойство Resources. Таким образом, вы можете добавить локальный словарь ресурсов в любой FrameworkElement.

Здесь и на странице , и в рамке есть словари ресурсов, и оба содержат ресурс под названием "приветствие". TextBlock именем 'textBlock2' находится внутри Границы, поэтому поиск ресурсов сначала обращается к ресурсам Границы, затем к ресурсам страницы, и затем к ресурсам приложения. TextBlock будет отображать «Hola mundo».

Чтобы получить доступ к ресурсам этого элемента из кода, используйте свойство Resources этого элемента. Доступ к ресурсам FrameworkElementв коде, а не XAML, будет выглядеть только в этом словаре, а не в словарях родительского элемента.

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <x:String x:Key="greeting">Hello world</x:String>
    </Page.Resources>
    
    <StackPanel>
        <!-- Displays "Hello world" -->
        <TextBlock x:Name="textBlock1" Text="{StaticResource greeting}"/>

        <Border x:Name="border">
            <Border.Resources>
                <x:String x:Key="greeting">Hola mundo</x:String>
            </Border.Resources>
            <!-- Displays "Hola mundo" -->
            <TextBlock x:Name="textBlock2" Text="{StaticResource greeting}"/>
        </Border>

        <!-- Displays "Hola mundo", set in code. -->
        <TextBlock x:Name="textBlock3"/>
    </StackPanel>
</Page>

    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            textBlock3.Text = (string)border.Resources["greeting"];
        }
    }
    MainPage::MainPage()
    {
        InitializeComponent();
        textBlock3().Text(unbox_value<hstring>(border().Resources().TryLookup(winrt::box_value(L"greeting"))));
    }

Объединенные словари ресурсов

Объединенный словарь ресурсов объединяет один словарь ресурсов с другим, как правило, в отдельном файле.

Совет Можно создать файл словаря ресурсов в Microsoft Visual Studio с помощью параметра Добавить > новый элемент... > словарь ресурсов в меню Проект.

Здесь вы определяете словарь ресурсов в отдельном XAML-файле с именем Dictionary1.xaml.

<!-- Dictionary1.xaml -->
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MSDNSample">

    <SolidColorBrush x:Key="brush" Color="Red"/>

</ResourceDictionary>

Чтобы использовать этот словарь, вы объединяете его с словарем страницы:

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml"/>
            </ResourceDictionary.MergedDictionaries>

            <x:String x:Key="greeting">Hello world</x:String>

        </ResourceDictionary>
    </Page.Resources>

    <TextBlock Foreground="{StaticResource brush}" Text="{StaticResource greeting}" VerticalAlignment="Center"/>
</Page>

Вот что происходит в этом примере. В <Page.Resources>вы объявляете <ResourceDictionary>. Фреймворк XAML неявно создает словарь ресурсов при добавлении ресурсов в <Page.Resources>; однако в этом случае вам нужен не просто словарь ресурсов, а тот, который содержит объединенные словари.

Таким образом, вы объявляете <ResourceDictionary>, а затем добавляете элементы в коллекцию <ResourceDictionary.MergedDictionaries>. Каждая из этих записей принимает форму <ResourceDictionary Source="Dictionary1.xaml"/>. Чтобы добавить несколько словарей, просто добавьте <ResourceDictionary Source="Dictionary2.xaml"/> запись после первой записи.

После <ResourceDictionary.MergedDictionaries>…</ResourceDictionary.MergedDictionaries> вы можете при желании добавить дополнительные ресурсы в основной словарь. Вы используете ресурсы из объединенного словаря так же, как обычный словарь. В приведенном выше примере {StaticResource brush} находит ресурс в дочернем или объединенном словаре (Dictionary1.xaml), в то время как {StaticResource greeting} находит его в словаре главной страницы.

В последовательности поиска ресурсов словарь MergedDictionaries проверяется только после проверки всех остальных ключевых ресурсов в данном ResourceDictionary. После поиска на этом уровне поиск достигает объединенных словарей, и проверяется каждый элемент в Объединенных Словарей. Если существуют несколько объединенных словарей, эти словари проверяются в обратном порядке, в котором они объявляются в свойстве MergedDictionaries . В следующем примере, если и Dictionary2.xaml, и Dictionary1.xaml объявили один и тот же ключ, ключ из Dictionary2.xaml будет использоваться в первую очередь, так как он последний в наборе MergedDictionaries.

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml"/>
                <ResourceDictionary Source="Dictionary2.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Page.Resources>

    <TextBlock Foreground="{StaticResource brush}" Text="greetings!" VerticalAlignment="Center"/>
</Page>

В пределах любого ResourceDictionaryвыполняется проверка словаря на уникальность ключей. Однако эта область не распространяется между различными элементами в разных файлах MergedDictionaries.

Можно использовать комбинацию последовательности поиска соответствий и отсутствие применения уникальных ключей в областях объединенного словаря для создания последовательности резервных значений ресурсов ResourceDictionary. Например, вы можете сохранить пользовательские настройки для определенного цвета кисти в последнем объединенном словаре ресурсов в последовательности, используя словарь ресурсов, который синхронизируется с состоянием и пользовательскими данными приложения. Однако если настройки пользователя еще не существуют, можно определить ту же строку ключа для ресурса ResourceDictionary в исходном файле MergedDictionaries , и она может служить резервным значением. Помните, что любое значение, предоставленное в словаре первичных ресурсов, всегда проверяется перед проверкой объединенных словарей, поэтому если вы хотите использовать резервный метод, не определите этот ресурс в словаре первичных ресурсов.

Ресурсы темы и словари тем

ThemeResource похож на StaticResource, но поиск ресурсов повторно оценивается при изменении темы.

В этом примере для переднего плана TextBlock задано значение текущей темы.

<TextBlock Text="hello world" Foreground="{ThemeResource FocusVisualWhiteStrokeThemeBrush}" VerticalAlignment="Center"/>

Словарь тем — это особый тип объединенного словаря, который содержит ресурсы, которые зависят от темы, которую пользователь в настоящее время использует на своем устройстве. Например, "светлая" тема может использовать белую кисть цвета, в то время как "темная" тема может использовать темную кисть цвета. Кисть изменяет ресурс, с которым она связывается, но в остальном структура элемента управления, который использует кисть в качестве ресурса, может оставаться прежней. Чтобы воспроизвести поведение переключения тем в собственных шаблонах и стилях, вместо использования MergedDictionaries в качестве свойства для объединения элементов в основные словари используйте свойство ThemeDictionaries .

Каждый элемент ResourceDictionary в ThemeDictionaries должен иметь значение x:Key. Это строка, которая называет соответствующую тему, например Default, Dark, Light или HighContrast. Как правило, Dictionary1 и Dictionary2 определяют ресурсы с одинаковыми именами, но разными значениями.

Здесь вы используете красный текст для светлой темы и синего текста для темной темы.

<!-- Dictionary1.xaml -->
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MSDNSample">

    <SolidColorBrush x:Key="brush" Color="Red"/>

</ResourceDictionary>

<!-- Dictionary2.xaml -->
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MSDNSample">

    <SolidColorBrush x:Key="brush" Color="blue"/>

</ResourceDictionary>

В этом примере для переднего плана TextBlock задано значение текущей темы.

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <ResourceDictionary>
            <ResourceDictionary.ThemeDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml" x:Key="Light"/>
                <ResourceDictionary Source="Dictionary2.xaml" x:Key="Dark"/>
            </ResourceDictionary.ThemeDictionaries>
        </ResourceDictionary>
    </Page.Resources>
    <TextBlock Foreground="{StaticResource brush}" Text="hello world" VerticalAlignment="Center"/>
</Page>

Для словарей тем активный словарь, используемый для подстановки ресурсов, изменяется динамически, когда используется расширение разметки ThemeResource для создания ссылки, и система обнаруживает изменение темы. Подстановка, осуществляемая системой, основана на сопоставлении активной темы с x:Key конкретного словаря тем.

Это может быть полезно для изучения способа структурирования словарей тем в дизайнерских ресурсах XAML по умолчанию, которые идут параллельно шаблонам, используемым средой выполнения Windows по умолчанию для элементов управления. Откройте XAML-файлы в папке \(Program Files)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<версии пакета SDK>\Generic с помощью текстового редактора или интегрированной среды разработки. Обратите внимание, как словари тем определяются сначала в generic.xaml и как каждый словарь тем определяет одни и те же ключи. Затем каждый такой ключ ссылается на элементы композиции в различных ключевых элементах, которые находятся вне словарей тем и определены далее в XAML. Существует также отдельный файл themeresources.xaml для проектирования, который содержит только ресурсы темы и дополнительные шаблоны, а не шаблоны элементов управления по умолчанию. Области темы такие же, как вы увидите в generic.xaml.

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

Для получения дополнительной информации и списка тематических и системных ресурсов, доступных вашему приложению, см. в ресурсах темы XAML.

Поведение поиска для ссылок на ресурсы XAML

Поведение подстановки — это термин, описывающий, как система ресурсов XAML пытается найти ресурс XAML. Поиск осуществляется, когда ключ используется как ссылка на ресурс XAML откуда-либо в XAML приложения. Во-первых, система ресурсов имеет прогнозируемое поведение, в которой она проверяет наличие ресурса в зависимости от области видимости. Если ресурс не найден в исходной области, область расширяется. Поведение поиска продолжается во всех возможных расположениях и областях, в которых ресурс XAML может быть определен приложением или системой. Если все возможные попытки поиска ресурсов завершаются ошибкой, часто возникает ошибка. Обычно эти ошибки можно устранить во время процесса разработки.

Поведение подстановки для ссылок на ресурсы XAML начинается с объекта, в котором применяется конкретное использование, и его собственного свойства Resources. Если resourceDictionary существует, то resourceDictionary проверяется для элемента с запрошенным ключом. Этот первый уровень поиска редко имеет значение, потому что вы обычно не определяете ресурс, а затем ссылаетесь на него для одного и того же объекта. На самом деле, свойство Resources часто не существует здесь. Вы можете создавать ссылки на ресурсы XAML практически в любом месте XAML; вы не ограничены свойствами подклассов FrameworkElement.

Затем последовательность поиска проверяет следующий родительский объект в дереве объектов среды выполнения. Если FrameworkElement.Resources содержит ResourceDictionary, запрашивается элемент словаря с указанной строкой ключа. Если ресурс найден, процесс подстановки останавливается, и объект предоставляется там, где была сделана ссылка. В противном случае процесс подстановки движется к следующему родительскому уровню в направлении корня дерева объектов. Поиск продолжается рекурсивно вверх, пока не будет достигнут корневой элемент XAML, исчерпывая поиск всех возможных непосредственных ресурсов.

Замечание

Это распространенная практика определения всех непосредственных ресурсов на корневом уровне страницы, как для использования этого поведения поиска ресурсов, так и в качестве соглашения о стиле разметки XAML.

Если запрошенный ресурс не найден в непосредственных ресурсах, следующий шаг поиска — проверить свойство Application.Resources . Application.Resources — это лучшее место для размещения всех ресурсов, на которые ссылается несколько страниц в структуре навигации приложения.

Это важно

Порядок ресурсов, добавленных в ResourceDictionary, влияет на порядок их применения. Словарь XamlControlsResources переопределяет множество ключей ресурсов по умолчанию, и его следует сначала добавить в Application.Resources, чтобы он не переопределил другие пользовательские стили или ресурсы в приложении.

Шаблоны элементов управления имеют другое возможное расположение в поиске ссылок: словари тем. Словарь тем — это один XAML-файл с элементом ResourceDictionary в качестве корневого элемента. Тематический словарь может быть словарем, объединённым из Application.Resources. Словарь тем может также быть тематическим словарем контроля для пользовательского контрола с шаблоном.

Наконец, осуществляется поиск по ресурсам платформы. Ресурсы платформы включают шаблоны элементов управления, определенные для каждой темы системного пользовательского интерфейса, и определяют внешний вид всех элементов управления, используемых для пользовательского интерфейса в приложении среды выполнения Windows. Ресурсы платформы также включают набор именованных ресурсов, связанных с внешним видом и темами на уровне системы. Эти ресурсы технически являются элементом MergedDictionaries, поэтому они доступны для поиска из XAML или кода после загрузки приложения. Например, ресурсы системной темы включают ресурс с именем SystemColorWindowTextColor, который предоставляет определение цвета цвета приложения для сопоставления цвета текста приложения с цветом текста окна системы, который поступает из операционной системы и пользовательских настроек. Другие стили XAML для вашего приложения могут ссылаться на этот стиль, или код может получить значение подстановки ресурсов (и привести его к цвету в примере).

Для получения дополнительной информации и списка ресурсов, специфичных для темы и системных ресурсов, доступных приложению Windows, использующему XAML, см. ресурсы темы XAML.

Если запрошенный ключ по-прежнему не найден ни в одном из этих расположений, возникает ошибка или исключение синтаксического анализа XAML. В некоторых случаях исключение синтаксического анализа XAML может быть исключением во время выполнения, которое не обнаруживается действием компиляции разметки XAML или средой разработки XAML.

Из-за многоуровневого поведения поиска для словарей ресурсов, можно намеренно определить несколько элементов ресурсов, каждый из которых имеет совпадающее строковое значение с ключом, при условии, что каждый ресурс определён на отдельном уровне. Другими словами, хотя ключи должны быть уникальными в пределах любого заданного ResourceDictionary, требование уникальности не распространяется на процедуру поиска в целом. Во время поиска для ссылки на ресурс XAML используется только первый такой объект, который успешно извлекается, а затем останавливается поиск. Это поведение можно использовать для запроса одного ресурса XAML по ключу на различных позициях в XAML приложения, но при этом получить обратно разные ресурсы в зависимости от области, из которой была сделана ссылка на ресурс XAML, и как выполняется этот конкретный поиск.

Переадресация ссылок в ResourceDictionary

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

Ресурсы, определенные на уровне приложения, не могут ссылаться на немедленные ресурсы. Это эквивалентно попытке переадресации ссылки, так как ресурсы приложения обрабатываются сначала (при первом запуске приложения и перед загрузкой содержимого страницы навигации). Однако любой немедленный ресурс может ссылаться на ресурс приложения, и это может быть полезным способом предотвращения ситуаций с перенаправлением ссылок.

Ресурсы XAML должны быть общими

Для того чтобы объект существовал в ResourceDictionary, этот объект должен быть разделяемым.

Требуется совместное использование, так как, если дерево объектов приложения создается и используется во время выполнения, объекты не могут существовать в нескольких расположениях в дереве. Внутри системы ресурсов создаются копии значений ресурсов для использования в графе объектов приложения при запросе каждого ресурса XAML.

ResourceDictionary и XAML среды выполнения Windows в целом поддерживают эти объекты для совместного использования:

Вы также можете использовать пользовательские типы в качестве разделяемого ресурса, если следовать необходимым паттернам реализации. Вы определяете такие классы в коде резервного копирования (или в компонентах среды выполнения, которые вы включаете) и создаете экземпляры этих классов в XAML в качестве ресурса. Примерами могут служить источники объектных данных и реализации IValueConverter для привязки данных.

Пользовательские типы должны иметь конструктор по умолчанию, так как именно его использует парсер XAML для создания экземпляра класса. Пользовательские типы, используемые в качестве ресурсов, не могут иметь класс UIElement в их наследовании, так как UIElement никогда не может быть совместно использоваться (он всегда предназначен для представления всего одного элемента пользовательского интерфейса, существующего в одной позиции в графе объектов приложения среды выполнения).

Область использования UserControl

Элемент UserControl имеет особое поведение при поиске ресурсов, поскольку он обладает встроенными понятиями области определения и области использования. UserControl, который делает ссылку на ресурсы XAML из своей области определения, должен поддерживать поиск этого ресурса в своей последовательности поиска в области определения, то есть не может получить доступ к ресурсам приложения. Из области использования UserControl ссылка на ресурс обрабатывается как в последовательности поиска по направлению к корню страницы использования (как и любая другая ссылка из объекта в загруженном дереве объектов) и может получить доступ к ресурсам приложения.

ResourceDictionary и XamlReader.Load

Вы можете использовать ResourceDictionary либо как корневой элемент, либо как часть входных данных XAML для метода XamlReader. Load. Вы также можете включить ссылки на ресурсы XAML в код XAML, если все такие ссылки полностью автономны в XAML, отправленной для загрузки. XamlReader.Load анализирует XAML в контексте, который не знает о других объектах ResourceDictionary, даже не Application.Resources. Кроме того, не используйте {ThemeResource} из XAML, отправленного в XamlReader.Load.

Использование ResourceDictionary из кода

Большинство сценариев для ResourceDictionary обрабатываются исключительно в XAML. Вы объявляете контейнер ResourceDictionary и ресурсы в виде XAML-файла или набора узлов XAML в файле определения пользовательского интерфейса. А затем вы используете ссылки на ресурсы XAML для запроса этих ресурсов из других частей XAML. Тем не менее, существуют определенные сценарии, в которых приложение может потребоваться настроить содержимое ResourceDictionary с помощью кода, выполняемого во время выполнения приложения, или, по крайней мере, чтобы запросить содержимое ResourceDictionary , чтобы узнать, определен ли ресурс. Эти вызовы кода выполняются в экземпляре ResourceDictionary, поэтому сначала необходимо получить его — либо немедленный ResourceDictionary где-то в дереве объектов, получив FrameworkElement.Resourcesили Application.Current.Resources.

В коде C# или Microsoft Visual Basic можно ссылаться на ресурс в заданном ResourceDictionary с помощью индексатора (элемент). ResourceDictionary — это словарь с ключом строки, поэтому индексатор использует ключ строки вместо целочисленного индекса. В коде расширений компонентов Visual C++ (C++/CX) используйте Lookup.

При использовании кода для проверки или изменения ResourceDictionaryповедение API, таких как Lookup или Item, не предусматривает перехода от непосредственных ресурсов к ресурсам приложения; это обусловлено поведением синтаксического анализатора XAML, которое наблюдается только при загрузке страниц XAML. Во время выполнения область действия ключей является автономной для экземпляра ResourceDictionary , который вы используете в то время. Однако этот объем охватывает объединенные словари.

Кроме того, если вы запрашиваете ключ, который не существует в ResourceDictionary, ошибки может не быть; возвращаемое значение может быть просто указано как null. Если вы попытаетесь использовать возвращаемое значение NULL в качестве значения, возможно, по-прежнему возникает ошибка. Ошибка будет получена из метода задания свойства, а не вызова ResourceDictionary. Единственный способ, который можно избежать ошибки, заключается в том, что свойство принимает значение NULL в качестве допустимого значения. Обратите внимание, как это поведение резко отличается от поведения поиска XAML во время его синтаксического анализа: сбой при разрешении предоставленного ключа из XAML во время разбора приводит к ошибке синтаксического анализа XAML, даже в тех случаях, когда свойство могло бы принять null.

Объединенные словари ресурсов входят в область индекса основного словаря ресурсов, который ссылается на объединенный словарь во время выполнения. Другими словами, вы можете использовать элемент или воспользоваться функцией поиска в основном словаре, чтобы найти любые объекты, фактически определенные в объединенном словаре. В этом случае поведение подстановки напоминает поведение подстановки XAML во время синтаксического анализа: если в объединенных словарях есть несколько объектов с одинаковым ключом, возвращается объект из последнего добавленного словаря.

Вы можете добавлять элементы в существующий ResourceDictionary, используя метод Add (на C# или Visual Basic) или Insert (на C++/CX). Вы можете добавить элементы в непосредственные ресурсы или ресурсы приложения. Для любого из этих вызовов API требуется ключ, который удовлетворяет требованию, что каждый элемент в ResourceDictionary должен иметь ключ. Однако элементы, добавляемые в ResourceDictionary во время выполнения, не относятся к ссылкам на ресурсы XAML. Необходимый поиск ссылок на ресурсы XAML происходит при первом анализе XAML по мере загрузки приложения (или обнаружения изменения темы). Ресурсы, добавленные в коллекции во время выполнения, недоступны, а изменение ResourceDictionary не делает недействительным уже полученный ресурс из него, даже если изменить значение этого ресурса.

Вы также можете удалить элементы из ResourceDictionary во время выполнения, сделать копии некоторых или всех элементов или других операций. Список членов ResourceDictionary указывает, какие API доступны. Обратите внимание, что, так как ResourceDictionary имеет проецируемый API для поддержки своих базовых интерфейсов коллекции, параметры API отличаются в зависимости от того, используете ли вы C# или Visual Basic или C++/CX.

Словарь ресурсов (ResourceDictionary) и локализация

XAML ResourceDictionary может изначально содержать локализованные строки. Если это так, сохраните эти строки как ресурсы проекта вместо ResourceDictionary. Извлеките строки из XAML и вместо этого добавьте элементу значение директивы x:Uid . Затем определите ресурс в файле ресурсов. Укажите имя ресурса в форме XUIDValue.PropertyName и значение ресурса строки, которая должна быть локализована.

Поиск пользовательских ресурсов

Для расширенных сценариев можно реализовать класс, который может иметь другое поведение, чем поведение поиска ссылок на ресурс XAML, описанное в этом разделе. Для этого вы реализуете класс CustomXamlResourceLoader, и затем вы можете получить доступ к этому поведению с помощью расширения разметки CustomResource для ссылок на ресурсы вместо использования StaticResource или ThemeResource. Большинство приложений не будут иметь сценариев, требующих этого. Дополнительные сведения см. в разделе CustomXamlResourceLoader.