Search code examples
xamlbuttonwin-universal-appuwprounded-corners

XAML button with rounded edged with perfect semicircle at the sides


I have been trying for sometime now to create a button with rounded edges whose rounded edges are actually semicircles.
My idea of implementing this is to bind the CornerRadius of the Border to the half the height of the button (I know there's no way I can do a calculation in XAML, except maybe a converter). Alas, that seems impossible because TemplateBinding doesn't bring up any suggestion.

<ControlTemplate TargetType="Button">
    <Grid>
        <Border CornerRadius={???}>
            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                              Margin="{TemplateBinding Padding}"
                              FontSize="{TemplateBinding FontSize}"
                              FontFamily="{TemplateBinding FontFamily}" />
        </Border>
    </Grid>
</ControlTemplate>

Maybe I might have to create a new control derived from button with a CornerRadius dependency property. But before I go ahead, is there anyway to achieve it in XAML?
By the way, if it matters, I'm doing it for a UWP app?


Solution

  • But before I go ahead, is there anyway to achieve it in XAML?

    Yes, I think this is possible. But converter is needed

    I know there's no way I can do a calculation in XAML, except maybe a converter

    Yes, we need to calculate in the converter and the CornerRadius is a CornerRadius type, we can't directly binding a double type of Height/2 to it. Here I used Button's height to calculate the radius.

    My idea of implementing this is to bind the CornerRadius of the Border to the half the height of the button.

    I think there is no need to use a Border for the ControlTemplate of Button, Grid and ContentPresenter also have the CornerRadius property.

    For example here:

    <ControlTemplate TargetType="Button">
        <Grid x:Name="RootGrid" Background="{TemplateBinding Background}"
              CornerRadius="{Binding Height, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource cvt}}">
            <ContentPresenter x:Name="ContentPresenter" AutomationProperties.AccessibilityView="Raw"
                              BorderBrush="{TemplateBinding BorderBrush}"
                              BorderThickness="{TemplateBinding BorderThickness}"
                              ContentTemplate="{TemplateBinding ContentTemplate}"
                              ContentTransitions="{TemplateBinding ContentTransitions}"
                              Content="{TemplateBinding Content}"
                              HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                              Padding="{TemplateBinding Padding}"
                              VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                              CornerRadius="{Binding Height, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource cvt}}" />
        </Grid>
    </ControlTemplate>
    
    <local:HeightToCornerRadiusConverter x:Key="cvt" />
    

    My HeightToCornerRadiusConverter is like this:

    public class HeightToCornerRadiusConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            var height = (double)value;
            CornerRadius radius = new CornerRadius(height / 2);
            return radius;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }
    

    There is a problem here, as you can see that the CornerRadius is bound to the Height of the Button, so it is important that we need to set a height to Button when we use this style.