Search code examples
avaloniauiavalonia

Changing control themes in AvaloniaUI based on OS theme


I have several custom controls with custom styles in avalonia 11.0.5. How can i adjust styles to automatically change appearance according to OS Dark or Light theme

I fount solution, based on :

<Application xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Class="YourNamespace.App">
    <Application.Styles>
        <StyleInclude Source="LightTheme.axaml" />
        <StyleInclude Source="DarkTheme.axaml" />
    </Application.Styles>
</Application>

<!-- LightTheme.axaml -->
<Styles xmlns="https://github.com/avaloniaui"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style Selector="Button">
        <Setter Property="Background" Value="LightGray" />
    </Style>
</Styles>

<!-- DarkTheme.axaml -->
<Styles xmlns="https://github.com/avaloniaui"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style Selector="Button">
        <Setter Property="Background" Value="DarkGray" />
    </Style>
</Styles>

<Button Content="Click me" Classes="Button" />

but it doesn't work


Solution

  • You can apply theme conditional ResourceDictionaries under the ResourceDictionary.ThemeDictionaries element. With this strategy you will add SolidColorBrush to your ResourceDictionary and reference them by Key as DynamicResources. Then your Button only needs one style.

    <Application.Resources>
      <ResourceDictionary>
        <ResourceDictionary.ThemeDictionaries>
          <ResourceDictionary x:Key="Light">
            <ResourceDictionary.MergedDictionaries>
              <ResourceInclude Source='avares://Path.To/LightTheme.axaml'/>
            </ResourceDictionary.MergedDictionaries>
          </ResourceDictionary>
    
          <ResourceDictionary x:Key="Dark">
            <ResourceDictionary.MergedDictionaries>
              <ResourceInclude Source='avares://Path.To/DarkTheme.axaml'/>
            </ResourceDictionary.MergedDictionaries>
          </ResourceDictionary>
        </ResourceDictionary.ThemeDictionaries>
      </ResourceDictionary>
    </Application.Resources>
    

    You don't have to used merged dictionaries, you can put the SolidColorBrushes directly in the Light and Dark dictionaries above, but if you end up with a lot of them, it gets long and hard to read your App.axaml.

    LightTheme.axaml:

    <SolidColorBrush x:Key="Button.Background" Color="LightGray"/>
    

    DarkTheme.axaml:

    <SolidColorBrush x:Key="Button.Background" Color="DarkGray"/>
    
    <Button Content="Click me" Classes="Button" Background="{DynamicResource Button.Background}"/>