IAppearanceService¶
IAppearanceService provides a platform-agnostic way to access the appearance choices supported by the DeltaDesign theme and apply the chosen one. It allows your ViewModel to change the theme variant, color palette, and layout density at runtime without referencing any UI framework type directly.
Main features include:
- Theme variants — Provides access to available theme variants (
LightandDark). - Color palettes — Provides access to the color palettes in the DeltaDesign theme, such as
Nova,Helios,Terra,Vega, andAtlas. - Layout densities — Provides access to the layout densities available in the DeltaDesign theme (
Compact,Standard, andSpacious). - Immediate application — You can change a dedicated option of
IAppearanceServiceto immediately change the corresponding theme setting. - Bindable to selectors — The service implements the
INotifyPropertyChangedinterface and is designed to be bound directly to a ribbon gallery, a combo box, a menu, or any other selector.
Interface Definition¶
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¶
Each item in the ThemeVariants, Palettes, and Densities lists implements the IAppearanceOption interface:
Like the other service interfaces, the IAppearanceOption interface is free of UI framework types. It only contains a string property that specifies the caption of a theme option. However, actual implementations of the IAppearanceOption interface return richer objects, listed below:
IAppearanceOption Implementation |
Description |
|---|---|
ThemeOption class |
A light or dark theme variant. Additional properties include: - ThemeOption.Variant — the Avalonia.Styling.ThemeVariant applied when this option is chosen. |
PaletteOption class |
A color palette. Additional properties include: - PaletteOption.Palette — the palette applied when this option is chosen (Nova, Helios, Terra, Vega, Atlas, etc.);- PaletteOption.Accent — a read-only brush that represents the palette's accent color. The PaletteOption.Accent property allows you to show a color swatch in a selector, so the user can preview a palette before picking it. |
DensityOption class |
A layout density. Additional properties include: - DensityOption.Density — the density applied when this option is chosen (Compact, Standard, or Spacious). |
The IAppearanceService implementation returns these richer objects. For instance, the actual return value of IAppearanceService.SelectedPalette is a PaletteOption object.
How to Use IAppearanceService¶
- In your ViewModel, expose the
IAppearanceServiceservice as a property. - In your View, bind your selector controls to the members of this property.
Access the Service¶
You need to access the IAppearanceService service in your ViewModel to expose it as a property.
There are two ways to access an IAppearanceService object in a ViewModel:
- Through the
Service<T>()helper method. This is a convenient approach to obtain registered application services shipped with the Eremex Controls library. - Through constructor injection.
Service() Helper¶
Implement a helper Service<T>() method in your ViewModel to get a requested service using the static ApplicationServicesContext.GetRequiredService<T>() method.
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>();
}
In the App.axaml.cs file, ensure that Eremex application services are registered using SimpleServiceProvider and ApplicationServicesContext as follows:
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);
}
}
Constructor Injection¶
Implement a constructor in your ViewModel with IAppearanceService as a parameter. When you instantiate the ViewModel, pass the service object to this constructor.
public partial class MainViewModel : ObservableObject
{
public MainViewModel(IAppearanceService appearance)
{
Appearance = appearance;
}
public IAppearanceService Appearance { get; }
}
Expose the Service from the ViewModel¶
Expose IAppearanceService as a public property. UI controls in the View will bind to it directly:
The following example creates an Appearance property of the IAppearanceService type and initializes it using the Service<T> helper.
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>();
}
Example - Create a Palette Selector in a View¶
This example creates a combo box (ComboBoxEditor control) that lists the available theme palettes. When an item is selected in the control's dropdown menu, the corresponding palette is applied to the application.
In this example:
ComboBoxEditor.ItemsSourceis bound toAppearance.Palettesto list all available palettes in the dropdown menu.ComboBoxEditor.EditorValueis bound toAppearance.SelectedPalette. Picking an item in the control's dropdown applies the corresponding theme palette.- The ComboBoxEditor's item template displays the palette's accent color as a swatch next to the palette's name (header).
<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>
See the complete code in the Controls Demo application.
Example - Create a Density Selector¶
This example creates a combo box (ComboBoxEditor control) populated with layout density options. When a user selects an item, the corresponding layout density is automatically applied.
To show custom images for density values in the combo box, this example populates the control with items directly from the Eremex.AvaloniaUI.Themes.DeltaDesign.Density enumeration. The images are provided using a custom NameToImageConverter converter and displayed using the ComboBoxEditor.ItemTemplate property.
<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>
See the complete code in the Controls Demo application.
Change Theme Settings in Code¶
Use the SelectedThemeVariant, SelectedPalette, and SelectedDensity properties to change theme settings in code.
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.
}