Skip to main content

Custom Resources - Advanced

The overriding of color-related resources (like Brush) should be consistent with other resources. However, considering color interactions with light and dark themes, you may need to override separately for different themes.

Example:

I want to change the text color of the Button to purple, but to ensure good visibility in both light and dark modes, the designer suggests #9E28B3 for light mode and #B553C2 for dark mode.

Through the source code of Semi Avalonia /src/Semi.Avalonia/Controls/Button.axaml, we can see that the Button's Foreground is assigned as follows:

/src/Semi.Avalonia/Controls/Button.axaml
 <ControlTheme x:Key="{x:Type Button}" TargetType="Button">
<!--irrelavent code-->
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultPrimaryForeground}" />
<!--irrelavent code-->
</ControlTheme>

From the source code, we can see that ButtonDefaultPrimaryForeground is defined differently in light and dark themes as:

/src/Semi.Avalonia/Themes/Light/Button.axaml
<SolidColorBrush x:Key="ButtonDefaultPrimaryForeground" Color="#0077FA" />
/src/Semi.Avalonia/Themes/Dark/Button.axaml
<SolidColorBrush x:Key="ButtonDefaultPrimaryForeground" Color="#54A9FF" />

Therefore, we can reassign this resource in App.axaml as follows:

App.axaml
<Application
x:Class="Semi.Avalonia.Demo.App"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:semi="https://irihi.tech/semi"
RequestedThemeVariant="Light"
>
<Application.Styles>
<semi:SemiTheme Locale="zh-CN"/>
</Application.Styles>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="ButtonDefaultPrimaryForeground" Color="#9E28B3"/>
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="ButtonDefaultPrimaryForeground" Color="#B553C2"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

With this, the foreground color of buttons in the application will turn purple, with different values in light and dark modes.

Local Resource Overriding In Avalonia, a control retrieves resources by searching up the visual tree, finding them in resource dictionaries at each level until it finds a match. Thus, if you only want to change resources locally, you can override them in a resource dictionary nearby.

For example, I have several Buttons in a Window, but I only want the text color of Buttons within a StackPanel to be purple, then you can override the resources as follows:

<Window
x:Class="Semi.Avalonia.Demo.Views.MainWindow"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<WrapPanel>
<Button Content="Button 1.1"/>
<Button Content="Button 1.2"/>
</WrapPanel>
<StackPanel>
<StackPanel.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="ButtonDefaultPrimaryForeground" Color="#9E28B3"/>
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="ButtonDefaultPrimaryForeground" Color="#B553C2"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</StackPanel.Resources>
<Button Content="Button 2.1"/>
<Button Content="Button 2.2"/>
</StackPanel>
</Grid>
</Window>

This way, the buttons in the WrapPanel remain blue, but those in the StackPanel turn purple.