How to create/make rounded corner buttons in WPF?

Viewed 180377

I need to create a rounded corner glossy button in WPF. Can anyone please explain me what steps are needed?

17 Answers

I know this post is super old, but I have an answer that's surprisingly missing from the above and is also much simpler than most.

<Button>
    <Button.Resources>
        <Style TargetType="Border">
            <Setter Property="CornerRadius" Value="5"/>
        </Style>
    </Button.Resources>
</Button>

Since the default ControlTemplate for the Button control uses a Border element, adding a style for Border to the Button's resources applies that style to that Border. This lets you add rounded corners without having to make your own ControlTemplate and without any code. It also works on all varieties of Button (e.g. ToggleButton and RepeatButton).

The simplest solution without changing the default style is:

<Style TargetType="Button" x:Key="RoundButton">
    <Style.Resources>
        <Style TargetType="Border">
            <Setter Property="CornerRadius" Value="5" />
        </Style>
    </Style.Resources>
</Style>

Then just define your button like this:

<Button Style="{DynamicResource RoundButton}" />

despite the fact years have gone, i thing it's interesting to think about different way to approach it.

The way to recreate all the button template is an excellent way if you want to change everything but it's demoralizing for the beginner or if you just want to round corner of the button. It's true you don't have to change everything but at least you will must change events...

The way to modify "border" design in the button.resources is excellent too, if you are a beginner but it can be very boring to change all your buttons if you want to raise your design with more parameters.

There is a solution with a foot in both camps:

Put this code in window/page resources:

<Style TargetType="Border" x:Key="RoundMe">
    <Setter Property="CornerRadius" Value="4"/>
</Style>

Then for the buttons:

  <Button.Resources>
        <Style TargetType="Border" BasedOn="{StaticResource RoundMe}"/>
    </Button.Resources>

The most simple way is

<Button Content="OK"
            Background="#D73C46"
            Foreground="White"
            BorderThickness="0"
            Margin="10,25,10,5"
            Width="275"
            Height="34"
            FontSize="12"
            Click="CloseWindow"
            HorizontalAlignment="Center">
        <Button.Resources>
            <Style TargetType="{x:Type Border}">
                <Setter Property="CornerRadius" Value="3"/>
            </Style>
        </Button.Resources>
    </Button>

This is an adapted version of @Kishore Kumar 's answer that is simpler and more closely matches the default button style and colours. It also fixes the issue that his "IsPressed" trigger is in the wrong order and will never be executed since the "MouseOver" will take precedent:

<Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Grid x:Name="grid">
                        <Border x:Name="border" CornerRadius="2" BorderBrush="#707070" BorderThickness="1" Background="LightGray">
                            <ContentPresenter HorizontalAlignment="Center"
                                      VerticalAlignment="Center"
                                      TextElement.FontWeight="Normal">
                            </ContentPresenter>
                        </Border>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="Background" TargetName="border" Value="#BEE6FD"/>
                            <Setter Property="BorderBrush" TargetName="border" Value="#3C7FB1"/>
                        </Trigger>
                        <Trigger Property="IsPressed" Value="True">
                            <Setter Property="BorderBrush" TargetName="border" Value="#2C628B"/>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter Property="Opacity" TargetName="grid" Value="0.25"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>

You can use attached properties for setting button border radius (also the same will work for textboxes).

Create class for attached property

public class CornerRadiusSetter
{
    public static CornerRadius GetCornerRadius(DependencyObject obj) => (CornerRadius)obj.GetValue(CornerRadiusProperty);

    public static void SetCornerRadius(DependencyObject obj, CornerRadius value) => obj.SetValue(CornerRadiusProperty, value);

    public static readonly DependencyProperty CornerRadiusProperty =
        DependencyProperty.RegisterAttached(nameof(Border.CornerRadius), typeof(CornerRadius),
            typeof(CornerRadiusSetter), new UIPropertyMetadata(new CornerRadius(), CornerRadiusChangedCallback));

    public static void CornerRadiusChangedCallback(object sender, DependencyPropertyChangedEventArgs e)
    {
        Control control = sender as Control;

        if (control == null) return;

        control.Loaded -= Control_Loaded;
        control.Loaded += Control_Loaded;
    }

    private static void Control_Loaded(object sender, EventArgs e)
    {
        Control control = sender as Control;

        if (control == null || control.Template == null) return;

        control.ApplyTemplate();

        Border border = control.Template.FindName("border", control) as Border;

        if (border == null) return;

        border.CornerRadius = GetCornerRadius(control);
    }
}

Then you can use attached property syntax for multiple buttons without style duplicates:

<Button local:CornerRadiusSetter.CornerRadius="10">Click me!</Button>
<Button local:CornerRadiusSetter.CornerRadius="5, 0, 0, 5">Click me!</Button>
<Button local:CornerRadiusSetter.CornerRadius="3, 20, 8, 15">Click me!</Button>

When first starting I always disliked how a snippet of code with no explanation of location was given. So, there's this:

<Window x:Class ...>
    <Window.Resources>
        <Style x:Key="btnRound" TargetType="Button">
            <Style.Resources>
                <Style TargetType="Border">
                    <Setter Property="CornerRadius" Value="5"/>
                </Style>
            </Style.Resources>
        </Style>
    </Window.Resources>
    <Grid>
        <Button Content="Select" Click="Select_Click" Style="{StaticResource btnRound}" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Padding="10,2"/>
    </Grid>
</Window>

Although this question is long-since answered, I used an alternative approach that people might find simpler than any of these solutions (even Keith Stein's excellent answer). So I'm posting it in case it might help anyone.

You can achieve rounded corners on a button without having to write any XAML (other than a Style, once) and without having to replace the template or set/change any other properties. Just use an EventSetter in your style for the button's "Loaded" event and change it in code-behind.

(And if your style lives in a separate Resource Dictionary XAML file, then you can put the event code in a code-behind file for your resource dictionary.)

I do it like this:

Xaml Style:

<Style x:Key="ButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
    <EventSetter Event="Loaded"                   Handler="ButtonLoaded"/>
</Style>

Code-Behind:

public partial class ButtonStyles
{
    private void ButtonLoaded(object sender, RoutedEventArgs e)
    {
        if (!(sender is Button b))
            return;

        // Find the first top-level border we can.

        Border border = default;
        for (var i = 0; null == border && i < VisualTreeHelper.GetChildrenCount(b); ++i)
            border = VisualTreeHelper.GetChild(b, i) as Border;

        // If we found it, set its corner radius how we want.  

        if (border != null)
            border.CornerRadius = new CornerRadius(3);
    }
}

If you had to add the code-behind file to an existing resource dictionary xaml file, you can even have the code-behind file automatically appear underneath that XAML file in the Visual Studio Solution if you want. In a .NET Core project, just give it appropriate corresponding name (e.g if the resource Dictionary is "MyDictionary.xaml", name the code-behind file "MyDictionary.xaml.cs"). In a .NET Framework project, you need to edit the .csproj file in XML mode

I know its a old question but if you are looking to make the button on c# instead of xaml you can set the CornerRadius that will round your button.

Button buttonRouded = new Button
{
   CornerRadius = 10,
};

for anyone who wonders why their xaml doesn't work when they put in the button rounded code, check the previous line to see if it ends with />, and take out the / if it does.

Related