Search code examples
xamlmaui

Maui - How to create a circle button using xaml style


I want to make a xaml style for a circle button. A circle button would have equal width and height, and a corner radius of half the width. I would like to have a style where I only need to set one property, like the WidthRequest, and the other properties are calculated based on the property I set. So ideally I could have

<Button WidthRequest="120"
        Style="{StaticResource Circle}"/>

So the height and width would reference each other, and the corner radius would use the math converter to half the width. Something like

<Style x:Key="Square"
           TargetType="View">
        <Setter Property="WidthRequest" Value="{Binding HeightRequest, Source={RelativeSource Self}}"/>
        <Setter Property="HeightRequest" Value="{Binding WidthRequest, Source={RelativeSource Self}}"/>
    </Style>
    <Style x:Key="Circle"
           BasedOn="{StaticResource Square}"
           TargetType="Button">
        <Setter Property="CornerRadius" Value="{Binding WidthRequest, Source={RelativeSource Self}, Converter={StaticResource toolkit:MathExpressionConverter}, ConverterParameter='x/2'}"/>
    </Style>

However, The self reference in the style sheet references the Setter, instead of the control that consumes the style.

Work Around

As a work around I have a CircleButton control, below. This works but I'd prefer to use a style instead of a custom control

<?xml version="1.0" encoding="utf-8" ?>
<Button xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="App.CircleButton"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             WidthRequest="{Binding HeightRequest, Source={RelativeSource Self}}"
             HeightRequest="{Binding WidthRequest, Source={RelativeSource Self}}"
             CornerRadius="{Binding WidthRequest, Source={RelativeSource Self}, Converter={StaticResource MathExpressionConverter}, ConverterParameter='x/2'}">
    <Button.Resources>
        <ResourceDictionary>
            <toolkit:MathExpressionConverter x:Key="MathExpressionConverter" />
        </ResourceDictionary>
    </Button.Resources>
</Button>

Solution

  • I noticed how you're instantiating the Converter as

    Converter={StaticResource toolkit:MathExpressionConverter}
    

    Usually you put an instance in your own ResourceDictionary and instantiate it like this:

    Converter={StaticResource MathExpressionConverter}
    

    A full ResourceDictionary would look like:

    <ResourceDictionary>
        <!-- Insert the MathExpressionConverter into your resource dictionary -->
        <toolkit:MathExpressionConverter x:Key="MathExpressionConverter" />
    
        <!-- Your original Square definition -->
        <Style x:Key="Square" TargetType="View">
            <Setter Property="WidthRequest" Value="{Binding HeightRequest, Source={RelativeSource Self}}" />
            <Setter Property="HeightRequest" Value="{Binding WidthRequest, Source={RelativeSource Self}}" />
        </Style>
    
        <!-- Updated Circle definition -->
        <Style
            x:Key="Circle"
            BasedOn="{StaticResource Square}"
            TargetType="Button">
            <!-- Use your instance of the MathExpressionConverter here -->
            <Setter Property="CornerRadius" Value="{Binding Width, Source={RelativeSource Self}, Converter={StaticResource MathExpressionConverter}, ConverterParameter='x/2'}" />
        </Style>
    </ResourceDictionary>