Перейти к содержанию

IAppearanceService

IAppearanceService предоставляет платформенно-независимый способ получить параметры внешнего вида, поддерживаемые темой DeltaDesign, и применить выбранный. Он позволяет ViewModel менять вариант темы, цветовую палитру и плотность размещения во время работы приложения, не ссылаясь напрямую ни на какие типы UI-фреймворка.

Основные возможности:

  • Варианты темы — Предоставляет доступ к доступным вариантам темы (Light и Dark).
  • Цветовые палитры — Предоставляет доступ к цветовым палитрам темы DeltaDesign, таким как Nova, Helios, Terra, Vega и Atlas.
  • Плотность размещения — Предоставляет доступ к вариантам плотности размещения темы DeltaDesign (Compact, Standard и Spacious).
  • Немедленное применение — Изменение соответствующего параметра IAppearanceService сразу же меняет соответствующую настройку темы.
  • Привязка к селекторам — Сервис реализует интерфейс INotifyPropertyChanged и предназначен для прямой привязки к галерее ленты, выпадающему списку, меню или любому другому селектору.

Определение интерфейса

public interface IAppearanceService : INotifyPropertyChanged
{
    // A list of available theme variants (light/dark).
    IReadOnlyList<IAppearanceOption> ThemeVariants { get; }

    // A list of available color palettes.
    IReadOnlyList<IAppearanceOption> Palettes { get; }

    // A list of available layout densities.
    IReadOnlyList<IAppearanceOption> Densities { get; }

    // The chosen theme variant. Assigning it recolors the running application at once.
    IAppearanceOption SelectedThemeVariant { get; set; }

    // The chosen theme palette. Assigning it recolors the running application at once.
    IAppearanceOption SelectedPalette { get; set; }

    // The chosen density. Assigning it resizes the controls of the running application at once.
    IAppearanceOption SelectedDensity { get; set; }
}

IAppearanceOption

Каждый элемент списков ThemeVariants, Palettes и Densities реализует интерфейс IAppearanceOption:

public interface IAppearanceOption
{
    // The text shown for this choice.
    string Header { get; }
}

Как и другие интерфейсы сервисов, интерфейс IAppearanceOption не содержит типов UI-фреймворка. В нём есть только строковое свойство, задающее подпись параметра темы. Однако фактические реализации интерфейса IAppearanceOption возвращают более богатые объекты, перечисленные ниже:

Реализация IAppearanceOption Описание
Класс ThemeOption Светлый или тёмный вариант темы. Дополнительные свойства:
- ThemeOption.Variant — Avalonia.Styling.ThemeVariant, применяемый при выборе этого параметра.
Класс PaletteOption Цветовая палитра. Дополнительные свойства:
- PaletteOption.Palette — палитра, применяемая при выборе этого параметра (Nova, Helios, Terra, Vega, Atlas и т. д.);
- PaletteOption.Accent — кисть только для чтения, представляющая акцентный цвет палитры. Свойство PaletteOption.Accent позволяет показать в селекторе образец цвета, чтобы пользователь мог оценить палитру до её выбора.
Класс DensityOption Плотность размещения. Дополнительные свойства:
- DensityOption.Density — плотность, применяемая при выборе этого параметра (Compact, Standard или Spacious).

Реализация IAppearanceService возвращает эти более богатые объекты. Например, фактическое значение IAppearanceService.SelectedPalette — это объект PaletteOption.

Как использовать IAppearanceService

  1. В ViewModel предоставьте сервис IAppearanceService в виде свойства.
  2. В View привяжите контролы-селекторы к членам этого свойства.

Доступ к сервису

Чтобы предоставить сервис IAppearanceService в виде свойства, его нужно получить в ViewModel.

Получить объект IAppearanceService в ViewModel можно двумя способами:

  • С помощью вспомогательного метода Service<T>(). Это удобный способ получить зарегистрированные сервисы приложения, входящие в библиотеку Eremex Controls.
  • Через внедрение в конструктор.

Вспомогательный метод Service()

Реализуйте в ViewModel вспомогательный метод Service<T>(), который получает запрошенный сервис с помощью статического метода ApplicationServicesContext.GetRequiredService<T>().

using Eremex.AvaloniaUI.Controls.ApplicationServices;
using CommunityToolkit.Mvvm.Input;

public partial class MyViewModel : ObservableObject
{
    // Provides access to any registered service
    protected static T Service<T>() where T : class
        => ApplicationServicesContext.GetRequiredService<T>();

    public IAppearanceService Appearance { get; } = Service<IAppearanceService>();
}

Убедитесь, что в файле App.axaml.cs сервисы приложения Eremex зарегистрированы с помощью SimpleServiceProvider и ApplicationServicesContext следующим образом:

public class App : Application
{
    public override void OnFrameworkInitializationCompleted()
    {
        RegisterApplicationServices();
        //...
    }

    static void RegisterApplicationServices()
    {
        // Register built-in services.
        var serviceProvider = new SimpleServiceProvider();
        ApplicationServicesContext.RegisterApplicationServices(serviceProvider.AddSingleton);
        ApplicationServicesContext.SetCurrent(serviceProvider);
    }
}

Внедрение в конструктор

Реализуйте в ViewModel конструктор с параметром типа IAppearanceService. При создании ViewModel передайте объект сервиса в этот конструктор.

public partial class MainViewModel : ObservableObject
{
    public MainViewModel(IAppearanceService appearance)
    {
        Appearance = appearance;
    }

    public IAppearanceService Appearance { get; }
}

Предоставление сервиса из ViewModel

Предоставьте IAppearanceService в виде открытого свойства. Контролы в View будут привязываться к нему напрямую.

В этом примере создаётся свойство Appearance типа IAppearanceService, которое инициализируется с помощью вспомогательного метода Service<T>.

public partial class MainViewModel : ObservableObject
{
    public IAppearanceService Appearance { get; }

    public MainViewModel(ThemeVariant? startupThemeVariant = null)
    {
        Appearance = Service<IAppearanceService>();
        Appearance.SelectedThemeVariant = FindTheme(startupThemeVariant);
        //...
    }

    private IAppearanceOption? FindTheme(ThemeVariant? variant)
        => variant is null
            ? null
            : Appearance.ThemeVariants.FirstOrDefault(
                x => string.Equals(x.Header, variant.ToString(), StringComparison.OrdinalIgnoreCase));

    // Provides access to any registered service
    protected static T Service<T>() where T : class
        => ApplicationServicesContext.GetRequiredService<T>();
}

Пример - создание селектора палитры в View

В этом примере создаётся выпадающий список (контрол ComboBoxEditor) с доступными палитрами темы. При выборе элемента в выпадающем меню контрола соответствующая палитра применяется к приложению.

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

  • ComboBoxEditor.ItemsSource привязано к Appearance.Palettes, чтобы показать все доступные палитры в выпадающем меню.
  • ComboBoxEditor.EditorValue привязано к Appearance.SelectedPalette. Выбор элемента в выпадающем меню контрола применяет соответствующую палитру темы.
  • Шаблон элемента ComboBoxEditor отображает акцентный цвет палитры в виде образца рядом с её названием (заголовком).
<mxe:ComboBoxEditor x:Name="themePaletteComboBox"
                    ItemsSource="{Binding Appearance.Palettes}"
                    EditorValue="{Binding Appearance.SelectedPalette}"
                    IsTextEditable="False"
                    ApplyItemTemplateToEditBox="True"
                    Width="150" Margin="0,0,10,0">
    <mxe:ComboBoxEditor.ItemTemplate>
        <DataTemplate x:DataType="appsvc:PaletteOption">
            <StackPanel Orientation="Horizontal" Spacing="8">
                <Border Width="12" Height="12" CornerRadius="2" VerticalAlignment="Center"
                        Background="{Binding Accent}"
                        BorderThickness="1"
                        BorderBrush="{DynamicResource Outline/Neutral/Transparent/Medium}"/>
                <TextBlock Text="{Binding Header}" VerticalAlignment="Center"/>
            </StackPanel>
        </DataTemplate>
    </mxe:ComboBoxEditor.ItemTemplate>
</mxe:ComboBoxEditor>

Полный код приведён в демонстрационном приложении Controls Demo.

Пример - создание селектора плотности

В этом примере создаётся выпадающий список (контрол ComboBoxEditor), заполненный вариантами плотности размещения. При выборе элемента соответствующая плотность размещения применяется автоматически.

Чтобы показать в выпадающем списке собственные изображения для значений плотности, пример заполняет контрол элементами непосредственно из перечисления Eremex.AvaloniaUI.Themes.DeltaDesign.Density. Изображения предоставляются собственным конвертером NameToImageConverter и отображаются с помощью свойства ComboBoxEditor.ItemTemplate.

<mxe:ComboBoxEditor x:Name="densityComboBox"
                    ItemsSource="{mxc:EnumItemsSource EnumType=ddt:Density, ShowImages=True,
                                  NameToImageConverter={views:DensityToIconConverter}}"
                    EditorValueChanged="DensityComboBoxEditor_EditorValueChanged"
                    IsTextEditable="False"
                    Margin="0,0,10,0">
    <mxe:ComboBoxEditor.ItemTemplate>
        <DataTemplate x:DataType="mxc:EnumMemberInfo">
            <StackPanel Orientation="Horizontal" Spacing="8">
                <Image Source="{Binding Image}" Stretch="None" VerticalAlignment="Center"/>
                <TextBlock Text="{Binding Name}" VerticalAlignment="Center"/>
            </StackPanel>
        </DataTemplate>
    </mxe:ComboBoxEditor.ItemTemplate>
</mxe:ComboBoxEditor>

Полный код приведён в демонстрационном приложении Controls Demo.

Изменение настроек темы в коде

Чтобы изменить настройки темы в коде, используйте свойства SelectedThemeVariant, SelectedPalette и SelectedDensity.

public IAppearanceService Appearance { get; } = Service<IAppearanceService>();

public void ChangeThemeSettings() 
{
    Appearance.SelectedThemeVariant = Appearance.ThemeVariants[0]; // Switch to the default theme variant.
    Appearance.SelectedPalette = Appearance.Palettes[2];  // Apply the third palette.
    Appearance.SelectedDensity = Appearance.Densities[0]; // Switch to the most compact density.
}



* Эта страница переведена с использованием технологий машинного перевода.