Ссылки на ресурсы ResourceDictionary и XAML
Вы можете определить пользовательский интерфейс или ресурсы для приложения с помощью XAML. Ресурсы обычно являются определениями некоторых объектов, которые вы ожидаете использовать несколько раз. Чтобы получить ссылку на ресурс XAML позже, укажите ключ для ресурса, который действует как его имя. Вы можете ссылаться на ресурс в приложении или на любой странице XAML. Вы можете определить свои ресурсы с помощью элемента ResourceDictionary из среды выполнения Windows XAML. Затем можно ссылаться на ресурсы с помощью расширения разметки 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}
ищет ресурс с ключом greeting, который назначен свойству Text объекта TextBlock.
Обратите внимание , что понятия, связанные с ResourceDictionary , не путаются с действиями сборки ресурсов , файлами ресурса (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"
. Однако существует несколько других способов указать ключ:
- Style и 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.
Здесь Style имеет неявный ключ typeof(Button), а поскольку Button внизу страницы не определяет свойство Style, выполняется поиск стиля с ключом 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 код не возвращается в Application.Resources
словарь, если ресурсы не найдены в первом словаре.
В этом примере показано, как получить 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 может иметь resourceDictionary
FrameworkElement — это базовый класс, от которого наследуют элементы управления, имеющий свойство Resources. Таким образом, вы можете добавить локальный словарь ресурсов в любой FrameworkElement.
Здесь Page и Border имеют словари ресурсов, а также содержат ресурс с именем greeting. 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 . Если существуют несколько объединенных словарей, эти словари проверяются в обратном порядке, в котором они объявляются в свойстве 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. Как правило, и Dictionary2
определяет ресурсы с одинаковыми именами, Dictionary1
но разными значениями.
Здесь вы используете красный текст для светлой темы и синего текста для темной темы.
<!-- 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 version>\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, предоставляющий определение Color, которое устанавливает соответствие между цветом текста приложения и цветом текста системных окон, задаваемым параметрами операционной системы и настройками пользователя. Другие стили XAML для вашего приложения могут ссылаться на этот стиль, или код может получить значение подстановки ресурсов (и привести его к цвету в примере).
См. сведения, а также список ресурсов темы и системных ресурсов, которые доступны для приложений для Windows на XAML, в руководстве по ресурсам темы XAML.
Если запрошенный ключ по-прежнему не найден ни в одном из этих расположений, возникает ошибка или исключение синтаксического анализа XAML. В некоторых случаях исключение синтаксического анализа XAML может быть исключением во время выполнения, которое не обнаруживается действием компиляции разметки XAML или средой разработки XAML.
Из-за многоуровневого поведения подстановки для словарей ресурсов можно намеренно определить несколько элементов ресурсов, каждый из которых имеет то же строковое значение, что и ключ, если каждый ресурс определен на другом уровне. Иными словами, хотя ключи должны быть уникальными в рамках любого элемента ResourceDictionary, требование уникальности не распространяется на всю последовательность поведения поиска. Во время поиска для ссылки на ресурс XAML используется только первый такой объект, который успешно извлекается, а затем останавливается поиск. Это поведение можно использовать для запроса одного ресурса XAML по ключу на различных позициях в XAML приложения, но получить разные ресурсы обратно в зависимости от области, из которой была сделана ссылка на ресурс XAML и как выполняется этот конкретный поиск.
Переадресация ссылок в ResourceDictionary
Ссылки на ресурсы XAML в определенном словаре ресурсов должны ссылаться на ресурс, который уже определен с помощью ключа, и этот ресурс должен отображаться лексически перед ссылкой на ресурс. Переадресация ссылок на ресурсы XAML не может быть разрешена ссылкой на ресурсы XAML. По этой причине при использовании ссылок на ресурсы XAML из другого ресурса необходимо разработать структуру словаря ресурсов, чтобы ресурсы, используемые другими ресурсами, сначала определены в словаре ресурсов.
Ресурсы, определенные на уровне приложения, не могут ссылаться на немедленные ресурсы. Это эквивалентно попытке переадресации ссылки, так как ресурсы приложения обрабатываются сначала (при первом запуске приложения и перед загрузкой содержимого страницы навигации). Однако любой немедленный ресурс может ссылаться на ресурс приложения, и это может быть полезным способом предотвращения ситуаций с перенаправлением ссылок.
Ресурсы XAML должны быть общими
Чтобы объект мог существовать в ResourceDictionary, этот объект должен находиться в общем доступе.
Требуется совместное использование, так как, если дерево объектов приложения создается и используется во время выполнения, объекты не могут существовать в нескольких расположениях в дереве. Внутри системы ресурсов создаются копии значений ресурсов для использования в графе объектов приложения при запросе каждого ресурса XAML.
ResourceDictionary и XAML среды выполнения Windows в целом поддерживают следующие объекты для общего использования:
- Стили и шаблоны (Style и классы, производные от FrameworkTemplate).
- Кисти и цвета (классы, производные от Brush, и значения Color).
- Типы анимации, включая Storyboard.
- Преобразования (классы, производные от GeneralTransform).
- Matrix и Matrix3D.
- Значения Point.
- Некоторые другие структуры, связанные с пользовательским интерфейсом, например Thickness и CornerRadius.
- Встроенные типы данных в языке XAML
Вы также можете использовать пользовательские типы в качестве общего ресурса, если следовать необходимым шаблонам реализации. Вы определяете такие классы в коде резервного копирования (или в компонентах среды выполнения, которые вы включаете) и создаете экземпляры этих классов в 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 с помощью индексатора (item). ResourceDictionary — это словарь с ключом строки, поэтому индексатор использует ключ строки вместо целочисленного индекса. В коде расширений компонентов Visual C++ (C++/CX) используйте поиск.
Во время использования кода для проверки или изменения ResourceDictionary такие API, как Lookup или Item, не переходят от непосредственных ресурсов к ресурсам приложения. Это поведение анализатора XAML, которое вызывается только при загрузке страниц XAML. Во время выполнения область действия ключей является автономной для экземпляра ResourceDictionary , который вы используете в то время. Но эта область не распространяется на MergedDictionaries.
Кроме того, если вы запросите ключ, который не существует в ResourceDictionary, ошибка может не возникнуть, и возвращаемое значение может быть просто равно NULL. Если вы попытаетесь использовать возвращаемое значение NULL в качестве значения, возможно, по-прежнему возникает ошибка. Ошибка будет получена из метода задания свойства, а не вызова ResourceDictionary . Единственный способ, который можно избежать ошибки, заключается в том, что свойство принимает значение NULL в качестве допустимого значения. Обратите внимание, что это поведение контрастирует с поведением подстановки XAML во время анализа XAML; Сбой разрешения предоставленного ключа из XAML во время синтаксического анализа приводит к ошибке синтаксического анализа XAML, даже в тех случаях, когда свойство может принять значение NULL.
Объединенные словари ресурсов включаются в область индекса основного словаря ресурсов, ссылающегося на объединенный словарь во время выполнения. Другими словами, можно использовать Item или Lookup основного словаря для поиска любых объектов, которые были фактически определены в объединенном словаре. В этом случае поведение подстановки напоминает поведение подстановки 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.
См. также
- ResourceDictionary
- Обзор XAML
- Расширение разметки StaticResource
- Расширение разметки ThemeResource
- Ресурсы темы XAML
- Настройка стиля элементов управления
- Атрибут x:Key
Windows developer