Primary APIs:
ControlThemeStyleStylesThemeVariantThemeVariantScopeResourceDictionaryApplication.RequestedThemeVariantStyledElement.ThemeImportant members:
ControlTheme.TargetTypeControlTheme.BasedOnStyle.SettersResourceDictionary.ThemeDictionariesResourceDictionary.MergedDictionariesApplication.ResourcesTopLevel.RequestedThemeVariantReference source files:
src/Avalonia.Base/Styling/ControlTheme.cssrc/Avalonia.Base/Styling/Style.cssrc/Avalonia.Base/Styling/ThemeVariant.cssrc/Avalonia.Controls/ThemeVariantScope.cssrc/Avalonia.Base/Controls/ResourceDictionary.cssrc/Avalonia.Controls/Application.csDefault approach for this skill:
.axaml.Recommended layering:
Application.Resources.Application.Resources.ThemeDictionaries.ControlTheme entries keyed by explicit resource names.Theme="{StaticResource ...}".<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MyApp.App">
<Application.Resources>
<SolidColorBrush x:Key="BrandPrimaryBrush">#2F6FED</SolidColorBrush>
<SolidColorBrush x:Key="BrandForegroundBrush">White</SolidColorBrush>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="BrandSurfaceBrush">#F7F9FC</SolidColorBrush>
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="BrandSurfaceBrush">#1B1E24</SolidColorBrush>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<ControlTheme x:Key="BrandButtonTheme" TargetType="Button">
<Setter Property="Background" Value="{DynamicResource BrandPrimaryBrush}" />
<Setter Property="Foreground" Value="{DynamicResource BrandForegroundBrush}" />
<Setter Property="Padding" Value="12,8" />
<Setter Property="CornerRadius" Value="8" />
</ControlTheme>
</Application.Resources>
</Application>
<StackPanel xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Spacing="8">
<Border Background="{DynamicResource BrandSurfaceBrush}" Padding="12">
<TextBlock Text="Themed surface" />
</Border>
<Button Content="Primary Action"
Theme="{StaticResource BrandButtonTheme}" />
</StackPanel>
Use this mode only when the user explicitly asks for code-only UI/theme setup.
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Styling;
public static class BrandTheme
{
public static void Apply(Application app)
{
var resources = app.Resources;
resources["BrandPrimaryBrush"] = new SolidColorBrush(Color.Parse("#2F6FED"));
resources["BrandForegroundBrush"] = Brushes.White;
var light = new ResourceDictionary();
light["BrandSurfaceBrush"] = new SolidColorBrush(Color.Parse("#F7F9FC"));
var dark = new ResourceDictionary();
dark["BrandSurfaceBrush"] = new SolidColorBrush(Color.Parse("#1B1E24"));
resources.ThemeDictionaries[ThemeVariant.Light] = light;
resources.ThemeDictionaries[ThemeVariant.Dark] = dark;
var brandButtonTheme = new ControlTheme(typeof(Button));
brandButtonTheme.Setters.Add(new Setter(Button.BackgroundProperty, resources["BrandPrimaryBrush"]));
brandButtonTheme.Setters.Add(new Setter(Button.ForegroundProperty, resources["BrandForegroundBrush"]));
brandButtonTheme.Setters.Add(new Setter(Button.PaddingProperty, new Thickness(12, 8)));
brandButtonTheme.Setters.Add(new Setter(Button.CornerRadiusProperty, new CornerRadius(8)));
resources["BrandButtonTheme"] = brandButtonTheme;
}
}
var button = new Button { Content = "Primary Action" };
button.Theme = (ControlTheme)Application.Current!.Resources["BrandButtonTheme"]!;
Set app-wide variant:
Application.Current!.RequestedThemeVariant = ThemeVariant.Dark;
Set subtree variant scope in XAML:
<ThemeVariantScope xmlns="https://github.com/avaloniaui"
RequestedThemeVariant="Light">
<Border Background="{DynamicResource BrandSurfaceBrush}" />
</ThemeVariantScope>
Guidance:
ThemeVariantScope for isolated previews/editors.DynamicResource for keys expected to change by variant.Theme key missing or wrong key/type.ControlTheme.TargetType does not match the control type.ThemeDictionaries.StaticResource where DynamicResource is needed.Application.Resources.Default mode:
ControlTheme declarations in XAML.XAML-first complete usage:
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MyApp.App"
RequestedThemeVariant="Default">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="PageBackgroundBrush" Color="#F7F9FC" />
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="PageBackgroundBrush" Color="#171A20" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<ControlTheme x:Key="PrimaryButtonTheme" TargetType="Button">
<Setter Property="Background" Value="#2F6FED" />
<Setter Property="Foreground" Value="White" />
</ControlTheme>
</ResourceDictionary>
</Application.Resources>
</Application>
Code-only alternative (on request):
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Styling;
var app = Application.Current!;
app.Resources.ThemeDictionaries[ThemeVariant.Light] = new ResourceDictionary
{
["PageBackgroundBrush"] = new SolidColorBrush(Color.Parse("#F7F9FC"))
};
app.Resources.ThemeDictionaries[ThemeVariant.Dark] = new ResourceDictionary
{
["PageBackgroundBrush"] = new SolidColorBrush(Color.Parse("#171A20"))
};
var primaryButton = new ControlTheme(typeof(Button));
primaryButton.Setters.Add(new Setter(Button.BackgroundProperty, new SolidColorBrush(Color.Parse("#2F6FED"))));
primaryButton.Setters.Add(new Setter(Button.ForegroundProperty, Brushes.White));
app.Resources["PrimaryButtonTheme"] = primaryButton;