Search code examples
c#avaloniauiavalonia

Avalonia style selector doen't works on derived classes


I'm having an issue to style my custom control derived from button.

I inherited the Button class to add a DependencyProperty to it:

public class IconButton : Button, IStyleable
{
    Type IStyleable.StyleKey => typeof(Button);

    public static readonly StyledProperty<string> IconProperty =
        AvaloniaProperty.Register<IconButton, string>(nameof(Icon));

    public string Icon
    {
        get { return GetValue(IconProperty); }
        set { SetValue(IconProperty, value); }
    }
}

Now I want to create a style targetting only this derived class:

    <Styles xmlns="https://github.com/avaloniaui"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:i="clr-namespace:Projektanker.Icons.Avalonia;assembly=Projektanker.Icons.Avalonia"
            xmlns:cc="*****.*****.CustomControls">
        <Design.PreviewWith>
            <Border Padding="20">
              <StackPanel Orientation="Vertical">
                <cc:IconButton Content="hello custom" Icon="fab fa-github"/>
                <Button Content="hello"/>
              </StackPanel>
            </Border>
        </Design.PreviewWith>
    
      <Style Selector=":is(cc|IconButton)">
        <Setter Property="Background" Value="Red"/>
        <Setter Property="Template">
          <Setter.Value>
            <ControlTemplate>
              <StackPanel Orientation="Horizontal">
                <i:Icon Value="{TemplateBinding Icon}" />
                <TextBlock Text="{TemplateBinding Content}" />
              </StackPanel>
            </ControlTemplate>
          </Setter.Value>
        </Setter>
      </Style>
    </Styles>

enter image description here

AS you can see, the content is not my control template as the icon is not visible and the background is not red. Therefore I can't use my dependencyproperty.

Any suggestions or is it not supported by the language? I read on the documentation that is(****) for selector is intended to support derived type so I would expect my code to be working :(

Thx for help.


Solution

  • Try to remove IStyleable and your overriden StyleKey. You are telling the selector that it should look for a Button style and not your style.

    Happy coding Tim

    PS I cannot test it on my own right now, so if it doesn't work please tell me here.


    Update: I just made a blank new project and tested your code. Once I remove the StyleKey, it works:

    enter image description here

    This is the modified IconButton:

    public class IconButton : Button
    {
        public static readonly StyledProperty<string> IconProperty =
            AvaloniaProperty.Register<IconButton, string>(nameof(Icon));
        
        public string Icon
        {
            get { return GetValue(IconProperty); }
            set { SetValue(IconProperty, value); }
        }
    }
    

    If you are able to upload a minimal sample on Github, I can have a look what may be wrong.


    Update 2: Looking into your demo App I see that you use a third party icon lib. The lib requires you to configure a special service at start up, see: https://github.com/Projektanker/Icons.Avalonia#1-register-icon-providers-on-app-start-up

    I send you a PR which fixes your issue.

    enter image description here

    Happy coding Tim