How To Use Theme Variants
Because theme variants are deeply integrated into resources system, it is important to understand the Avalonia resources first.
Introduction
In Avalonia, a theme variant
refers to a specific visual appearance of control based on a chosen theme.
By using theme variants, developers can create visually appealing and consistent user interfaces that adapt to different user preferences or system settings. For example, an application may provide a light theme variant with a white background and black text, as well as a dark theme variant with a black background and white text. The user can choose their preferred theme, and the application will adjust its appearance accordingly.
Avalonia's built-in themes, SimpleTheme
and FluentTheme
, seamlessly support Dark
and Light
variants without extra code. This allows applications to adapt dynamically based on system preferences while using build-in controls. For advanced customization, this documentation explains defining custom variant-dependent resources and their referencing.
Switching current theme variant
By default, Avalonia inherits theme variant set by user preferences system-wide. Application has control over theme variants through two important properties: ActualThemeVariant and RequestedThemeVariant. These properties allow to manage and switch theme variants at different levels within your application.
ActualThemeVariant
Property
The ActualThemeVariant read-only property is used to retrieve the UI theme currently in use by a control, window, or application. It represents the theme variant that is actively applied to the element.
This property is available on each control and is inherited down the tree. Its value also used by the styling system while accessing theme dictionaries
.
RequestedThemeVariant
Property
The RequestedThemeVariant property allows to override theme variant and specify a desired variant for a Application
, Window
(TopLevel
) or ThemeVariantScope
.
To override global application variant instead of using system default:
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="AvaloniaApplication.App"
RequestedThemeVariant="Dark">
<Application.Styles>
<FluentTheme />
</Application.Styles>
</Application>
Or it is possible to redefine theme variant per specific subtree using ThemeVariantScope
control. In the example below Window uses Dark variant, while ThemeVariantScope inside redefines it with Light variant:
<Window xmlns="https://github.com/avaloniaui"
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
x:Class="AvaloniaApplication.MainWindow"
RequestedThemeVariant="Dark"
Background="Gray">
<StackPanel Spacing="5" Margin="5">
<Button Content="Dark button" />
<ThemeVariantScope RequestedThemeVariant="Light">
<Button Content="Light button" />
</ThemeVariantScope>
</StackPanel>
</Window>
If it's required to use reset RequestedThemeVariant value, RequestedThemeVariant="Default"
value can be set on it.
Changing Window RequestedThemeVariant also affects window decorations variant on platform where it is supported.
Defining and referencing custom variant specific resources
In Avalonia, theme variant specific resources can be defined in the ResourceDictionary
using the ThemeDictionaries
property.
Typically, developers use Light
or Dark
as the key for the theme variants. Using Default
as the key marks this specific theme dictionary as a fallback in case the theme variant or resource key is not found in other theme dictionaries.
Continuing previous example, let's add BackgroundBrush
and ForegroundBrush
with different values per theme variant:
<Window xmlns="https://github.com/avaloniaui"
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
x:Class="Sandbox.MainWindow"
RequestedThemeVariant="Dark"
Background="Gray">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key='Light'>
<SolidColorBrush x:Key='BackgroundBrush'>SpringGreen</SolidColorBrush>
<SolidColorBrush x:Key='ForegroundBrush'>Black</SolidColorBrush>
</ResourceDictionary>
<ResourceDictionary x:Key='Dark'>
<SolidColorBrush x:Key='BackgroundBrush'>DodgerBlue</SolidColorBrush>
<SolidColorBrush x:Key='ForegroundBrush'>White</SolidColorBrush>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Window.Resources>
<Window.Styles>
<Style Selector="Button">
<Setter Property="Background" Value="{DynamicResource BackgroundBrush}" />
<Setter Property="Foreground" Value="{DynamicResource ForegroundBrush}" />
</Style>
</Window.Styles>
<StackPanel Spacing="5" Margin="5">
<Button Content="Dark button"
Background="{DynamicResource BackgroundBrush}"
Foreground="{DynamicResource ForegroundBrush}" />
<ThemeVariantScope RequestedThemeVariant="Light">
<Button Content="Light button"
Background="{DynamicResource BackgroundBrush}"
Foreground="{DynamicResource ForegroundBrush}" />
</ThemeVariantScope>
</StackPanel>
</Window>
For more details about using resources please follow How To Use Resources page.