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


Словари ресурсов

Многоплатформенный пользовательский интерфейс приложения .NET (.NET MAUI) ResourceDictionary — это репозиторий для ресурсов, используемых приложением .NET MAUI. Типичные ресурсы, хранящиеся в ResourceDictionary стилях, шаблонах элементов управления, шаблонах данных, преобразователях и цветах.

Ресурсы XAML, хранящиеся в объекте ResourceDictionary , можно ссылаться и применять к элементам с помощью StaticResource расширения разметки или DynamicResource разметки. В C#ресурсы также можно определить в объекте ResourceDictionary , а затем ссылаться и применяться к элементам с помощью индексатора на основе строк.

Совет

В Visual Studio файл на основе ResourceDictionary XAML, который поддерживается файлом программной части, можно добавить в проект шаблоном элемента .NET MAUI ResourceDictionary (XAML ).

Создание ресурсов

Каждый VisualElement производный Resources объект имеет свойство, которое может ResourceDictionary содержать ресурсы. Аналогичным образом производный Application Resources объект имеет свойство, которое может ResourceDictionary содержать ресурсы.

Приложение .NET MAUI может содержать только один класс, производный от Application, но часто использует многие классы, производные от VisualElementстраниц, макетов и представлений. Любой из этих объектов может иметь значение свойства Resources , ResourceDictionary содержащего ресурсы. Выбор места для конкретного ResourceDictionary воздействия, в котором можно использовать ресурсы:

  • Ресурсы, ResourceDictionary подключенные к представлению, например Button или Label, могут применяться только к конкретному объекту.
  • Ресурсы в присоединенном ResourceDictionary к макету, например StackLayout или Grid, могут применяться к макету и всем дочерним элементам этого макета.
  • Ресурсы, определенные на ResourceDictionary уровне страницы, можно применять к странице и ко всем его дочерним элементам.
  • Ресурсы, определенные на ResourceDictionary уровне приложения, могут применяться во всем приложении.

За исключением неявных стилей, каждый ресурс в словаре ресурсов должен иметь уникальный строковый ключ, определенный атрибутом x:Key .

В следующем XAML показаны ресурсы, определенные на уровне ResourceDictionary приложения в файле App.xaml :

<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ResourceDictionaryDemo.App">
    <Application.Resources>

        <Thickness x:Key="PageMargin">20</Thickness>

        <!-- Colors -->
        <Color x:Key="AppBackgroundColor">AliceBlue</Color>
        <Color x:Key="NavigationBarColor">#1976D2</Color>
        <Color x:Key="NavigationBarTextColor">White</Color>
        <Color x:Key="NormalTextColor">Black</Color>

        <!-- Images -->
        <x:String x:Key="BackgroundImage">background</x:String>
        <x:String x:Key="MenuIcon">menu.png</x:String>
        <x:String x:Key="SearchIcon">search.png</x:String>

        <!-- Implicit styles -->
        <Style TargetType="NavigationPage">
            <Setter Property="BarBackgroundColor"
                    Value="{StaticResource NavigationBarColor}" />
            <Setter Property="BarTextColor"
                    Value="{StaticResource NavigationBarTextColor}" />
        </Style>

        <Style TargetType="ContentPage"
               ApplyToDerivedTypes="True">
            <Setter Property="BackgroundColor"
                    Value="{StaticResource AppBackgroundColor}" />
        </Style>

    </Application.Resources>
</Application>

В этом примере словарь ресурсов определяет Thickness ресурс, несколько Color ресурсов и два неявных Style ресурса.

Внимание

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

Использование ресурсов

Каждый ресурс имеет ключ, указанный с помощью атрибута x:Key , который становится его ключом словаря в элементе ResourceDictionary. Ключ используется для ссылки на ресурс из ResourceDictionary StaticResource расширения разметки XAML.DynamicResource

StaticResource Расширение разметки аналогично DynamicResource расширению разметки в том, что оба используют ключ словаря для ссылки на значение из словаря ресурсов. Однако в то время как StaticResource расширение разметки выполняет поиск одного словаря, DynamicResource расширение разметки сохраняет ссылку на ключ словаря. Поэтому при замене записи словаря, связанной с ключом, изменение применяется к визуальному элементу. Это позволяет вносить изменения ресурсов среды выполнения в приложение. Дополнительные сведения о расширениях разметки см. в разделе "Расширения разметки XAML".

В следующем примере XAML показано, как использовать ресурсы, а также определить дополнительный ресурс в StackLayout:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ResourceDictionaryDemo.MainPage"
             Title="Main page">
    <StackLayout Margin="{StaticResource PageMargin}"
                 Spacing="6">
        <StackLayout.Resources>
            <!-- Implicit style -->
            <Style TargetType="Button">
                <Setter Property="FontSize" Value="14" />
                <Setter Property="BackgroundColor" Value="#1976D2" />
                <Setter Property="TextColor" Value="White" />
                <Setter Property="CornerRadius" Value="5" />
            </Style>
        </StackLayout.Resources>

        <Label Text="This app demonstrates consuming resources that have been defined in resource dictionaries." />
        <Button Text="Navigate"
                Clicked="OnNavigateButtonClicked" />
    </StackLayout>
</ContentPage>

В этом примере объект использует неявный стиль, ContentPage определенный в словаре ресурсов уровня приложения. Объект StackLayout использует ресурс, определенный в словаре ресурсов уровня приложения, а Button объект использует PageMargin неявный стиль, определенный в StackLayout словаре ресурсов. Это приводит к отображению на следующем снимке экрана:

Использование ресурсов словаря ресурсов.

Внимание

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

Поведение подстановки ресурсов

Следующий процесс подстановки возникает, когда ресурс ссылается на StaticResource расширение разметки или DynamicResource разметки:

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

Таким образом, когда средство синтаксического анализа XAML обнаруживает StaticResource расширение разметки или DynamicResource выполняет поиск соответствующего ключа, перемещаясь по визуальному дереву, используя первое совпадение. Если этот поиск заканчивается на странице, а ключ еще не найден, средство синтаксического анализа XAML выполняет поиск ResourceDictionary присоединенного к объекту App . Если ключ по-прежнему не найден, создается исключение.

Переопределение ресурсов

Когда ресурсы используют ключи общего доступа, ресурсы, определенные ниже в визуальном дереве, будут иметь приоритет над теми, которые определены выше. Например, задание AppBackgroundColor ресурса AliceBlue на уровне приложения переопределяется набором Tealресурсов уровня AppBackgroundColor страницы. Аналогичным образом ресурс уровня AppBackgroundColor страницы переопределяется ресурсом уровня макета или представления AppBackgroundColor .

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

Можно ResourceDictionary также создать как автономный XAML-файл, который не поддерживается файлом программной части. Чтобы создать автономный ResourceDictionaryфайл, добавьте новый ResourceDictionary файл в проект с помощью шаблона элемента .NET MAUI ResourceDictionary (XAML) и удалите его файл кода программной части. Затем в XAML-файле удалите x:Class атрибут из ResourceDictionary тега вблизи начала файла. Кроме того, добавьте <?xaml-comp compile="true" ?> после заголовка XML, чтобы убедиться, что XAML будет скомпилирован.

Можно ResourceDictionary также создать как автономный XAML-файл, который не поддерживается файлом программной части. Чтобы создать автономный ResourceDictionaryфайл, добавьте новый ResourceDictionary файл в проект с помощью шаблона элемента .NET MAUI ResourceDictionary (XAML) и удалите его файл кода программной части. Затем в XAML-файле удалите x:Class атрибут из ResourceDictionary тега вблизи начала файла. По умолчанию автономный ResourceDictionary код xaml компилируется, если <?xaml-comp compile="false" ?> только не указан после заголовка XML.

Примечание.

ResourceDictionary Автономное действие должно иметь действие сборки MauiXaml.

В следующем примере XAML показан автономный ResourceDictionary файл MyResourceDictionary.xaml:

<?xml version="1.0" encoding="UTF-8" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
    <DataTemplate x:Key="PersonDataTemplate">
        <ViewCell>
            <Grid RowSpacing="6"
                  ColumnSpacing="6">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="0.5*" />
                    <ColumnDefinition Width="0.2*" />
                    <ColumnDefinition Width="0.3*" />
                </Grid.ColumnDefinitions>
                <Label Text="{Binding Name}"
                       TextColor="{StaticResource NormalTextColor}"
                       FontAttributes="Bold" />
                <Label Grid.Column="1"
                       Text="{Binding Age}"
                       TextColor="{StaticResource NormalTextColor}" />
                <Label Grid.Column="2"
                       Text="{Binding Location}"
                       TextColor="{StaticResource NormalTextColor}"
                       HorizontalTextAlignment="End" />
            </Grid>
        </ViewCell>
    </DataTemplate>
</ResourceDictionary>

В этом примере ResourceDictionary содержит один ресурс, который является объектом типа DataTemplate. MyResourceDictionary.xaml можно использовать путем объединения его в другой словарь ресурсов.

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

Словари ресурсов можно объединить путем объединения одного или нескольких ResourceDictionary объектов в другой ResourceDictionary.

Слияние словарей локальных ресурсов

Локальный ResourceDictionary файл можно объединить в другой ResourceDictionary , создав ResourceDictionary объект, свойство которого Source имеет имя файла XAML-файла с ресурсами:

<ContentPage ...>
    <ContentPage.Resources>
        <!-- Add more resources here -->
        <ResourceDictionary Source="MyResourceDictionary.xaml" />
        <!-- Add more resources here -->
    </ContentPage.Resources>
    ...
</ContentPage>

Этот синтаксис не создает экземпляр MyResourceDictionary класса. Вместо этого он ссылается на XAML-файл. По этой причине при задании Source свойства файл программной части не требуется, а x:Class атрибут можно удалить из корневого тега файла MyResourceDictionary.xaml .

Внимание

Свойство ResourceDictionary.Source можно задать только из XAML.

Объединение словарей ресурсов из других сборок

Кроме того, можно ResourceDictionary объединить его в другое ResourceDictionary MergedDictionaries , добавив его в свойство объекта ResourceDictionary. Этот метод позволяет объединять словари ресурсов независимо от сборки, в которой они находятся. Объединение словарей ресурсов из внешних сборок требует ResourceDictionary наличия действия сборки в MauiXaml, наличия файла программной части и определения x:Class атрибута в корневом теге файла.

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

Класс ResourceDictionary также определяет свойство MergedWith. Однако это свойство устарело и больше не должно использоваться.

В следующем примере кода показаны два словаря ресурсов, добавляемые в MergedDictionaries коллекцию уровня ResourceDictionaryстраницы:

<ContentPage ...
             xmlns:local="clr-namespace:ResourceDictionaryDemo"
             xmlns:theme="clr-namespace:MyThemes;assembly=MyThemes">
    <ContentPage.Resources>
        <ResourceDictionary>
            <!-- Add more resources here -->
            <ResourceDictionary.MergedDictionaries>
                <!-- Add more resource dictionaries here -->
                <local:MyResourceDictionary />
                <theme:DefaultTheme />
                <!-- Add more resource dictionaries here -->
            </ResourceDictionary.MergedDictionaries>
            <!-- Add more resources here -->
        </ResourceDictionary>
    </ContentPage.Resources>
    ...
</ContentPage>

В этом примере словарь ресурсов из той же сборки и словарь ресурсов из внешней сборки объединяются в словарь ресурсов уровня страницы. Кроме того, вы также можете добавить другие ResourceDictionary объекты в MergedDictionaries теги элементов свойств и другие ресурсы за пределами этих тегов.

Внимание

В нем может быть только один MergedDictionaries тег ResourceDictionaryэлемента свойства, но можно поместить в нее столько ResourceDictionary объектов, сколько требуется.

При совместном использовании ResourceDictionary ресурсов одинаковые x:Key значения атрибутов .NET MAUI использует следующий приоритет ресурсов:

  1. Локальные ресурсы словаря ресурсов.
  2. Ресурсы, содержащиеся в словарях ресурсов, которые были объединены через MergedDictionaries коллекцию, в обратном порядке они перечислены в свойстве MergedDictionaries .

Совет

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

Использование словаря ресурсов на основе XAML из кода

Словари ресурсов, определенные в XAML, можно использовать в коде, если ResourceDictionary он поддерживается файлом программной части. В Visual Studio файлы на основе ResourceDictionary XAML, поддерживаемые файлами кода, можно добавить в проект шаблоном элемента .NET MAUI ResourceDictionary (XAML ):

Снимок экрана: словари ресурсов, поддерживаемые кодом.

Словари ресурсов на основе XAML, поддерживаемые файлами кода, можно использовать из C# путем добавления их в MergedDictionaries коллекцию словаря ресурсов:

Resources.MergedDictionaries.Add(new MyMauiApp.Resources.Styles.MyColors());
Resources.MergedDictionaries.Add(new MyMauiApp.Resources.Styles.MyStyles());

Доступ к ресурсам по ключу из кода

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

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

// Retrieve the Primary color value which is in the page's resource dictionary
var hasValue = Resources.TryGetValue("Primary", out object primaryColor);

if (hasValue)
{
    myLabel.TextColor = (Color)primaryColor;
}

Это рекомендуемый подход, который гарантирует, что .NET MAUI не создает KeyNotFoundException исключение, если не удается получить ресурс из кода. Это может произойти, если объединенный словарь ресурсов состоит из ресурсов, определенных в XAML-файле, и встроенных ресурсов. Дополнительные сведения см. в статье о проблеме GitHub #11214.

Примечание.

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