Search code examples
xamlavaloniauiavalonia

AvaloniaUI Styles-pseudoclasses


I'm trying out styles in avalonia and most works, except for pseudoclasses, they just get ignored.

I have created a window and all styles are in there and I have created a user control (with a button on - the pseudoclasses are on the button), using the styles. I do not use code, only xaml to define the styles.

I have tried it out in the "Style Selector" for the button as "Button:pseudoclassname" and "Button.le:pseudoclassname". I have also tried "Button:pointerover" and "Button:hover" as the documentation mentions that that could be modified. No result. The styles for the pseudoclasses are all ignored, the others are all executed correct.

Is there something I'm doing wrong or is this a bug in avalonia ?

The xaml windows file:

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:views="clr-namespace:Hub.Views"
        xmlns:vm="using:Hub.ViewModels"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
        x:Class="Hub.Views.MainWindow"
        Icon="/Assets/avalonia-logo.ico"
        Width="200" Height="300"
        Title="Hub"
        Classes="le">

    <Window.Styles>
        <Style Selector="Window.le">
            <Setter Property="Background" Value="#191919"/>
        </Style>
        <Style Selector="Button.le">
            <Setter Property="Background" Value="green"/>
            <Setter Property="Foreground" Value="white"/>
        </Style>
        <Style Selector="Button.le:pointerover">
            <Setter Property="Background" Value="red"/>
            <Setter Property="Foreground" Value="white"/>
        </Style>
        <Style Selector="Button.le:pressed">
            <Setter Property="Background" Value="blue"/>
            <Setter Property="Foreground" Value="white"/>
        </Style>
        <Style Selector="TextBlock.le_update">
            <Setter Property="FontStyle" Value="Italic"/>
            <Setter Property="FontSize" Value="17"/>
            <Setter Property="FontFamily" Value="Arial, Verdana"/>
            <Setter Property="Foreground" Value="white"/>
            <Setter Property="Background" Value="transparent"/>
        </Style>
    </Window.Styles>
    
    <views:UpdateView/>

</Window>

The xaml user control file:

<UserControl 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" d:DesignWidth="800" d:DesignHeight="450"
             x:Class="Hub.Views.UpdateView">
    <DockPanel>
        <StackPanel DockPanel.Dock="Bottom">
            <Button Classes="le" HorizontalAlignment="Center" HorizontalContentAlignment="Center" Width="300">
                Check for updates
            </Button>
        </StackPanel>
        <StackPanel Spacing="5" Margin="5">
            <TextBlock Classes="le_update" HorizontalAlignment="Center" Margin="4">
                No updates for Hub.
            </TextBlock>
            <TextBlock Classes="le_update" HorizontalAlignment="Center" Margin="4">
                No updates for Engine.
            </TextBlock>
        </StackPanel>
    </DockPanel>
</UserControl>


Solution

  • Button's Background property does get affected by your style, but at that point it has no effect on the actual Button's background, because Background property controls only the normal state of the button.

    If you take a look at the default Button style here you can see that it passes its background to ContentPresenter via TemplateBinding:

        <Setter Property="Template">
          <ControlTemplate>
            <ContentPresenter x:Name="PART_ContentPresenter"
                              Background="{TemplateBinding Background}"
    

    but overrides ContentPresenter's background in a style like this:

      <Style Selector="Button:pointerover /template/ ContentPresenter#PART_ContentPresenter">
        <Setter Property="Background" Value="{DynamicResource ButtonBackgroundPointerOver}" />
    

    Since it's ContentPresenter that actually draws the background (Button is a lookless control), you'll see the button to have ButtonBackgroundPointerOver and not the Button's Background property value.

    So, you need to write a style that changes the inner ContentPresenter like this:

    <Style Selector="Button.le:pointerover /template/ ContentPresenter#PART_ContentPresenter">
      <Setter Property="Background" Value="green" />
    </Style>
    

    Unfortunately that makes your styles theme-dependent since control templates are different between default and fluent themes.