WPF: Elliptical Button

Screenshot of an elliptical button
Creating an elliptical button proved to be not as easy as some claimed. I would hardly describe it is “a snap”. <Button Shape="Ellipse"/> would be a snap, but the reality is nowhere near it.

From the other hand, not being a WPF expert, I managed to complete it within an hour with some googling, which means it is not that hard. Doing the same in Windows Forms would definitely give me much more headache. Full source code can be downloaded here (15K ZIP file).

The easiest way is to fake it: create a rectangular button and clip it to an ellipse, but this is cheating. The right way is to change the button control template. This post shows how to create a round button, but it is not pressible. This post demonstrates how to add a nice border with the “sink in” effect when the button is pressed. The result is still a little bit rough, but it works.

Everything is done in XAML, not a single line of code, but there is quite a few lines of it. I will provide it here in its entirety, just so you can feel the size of it:

<Window x:Class="EllipticalButton.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Eliptical Button"
    SizeToContent="WidthAndHeight"
    Background="Gray">

  <Window.Resources>
    <LinearGradientBrush x:Key="NormalButtonBorder" StartPoint=".5,0" EndPoint=".5,1">
      <GradientStop Color="Cyan" Offset="0"/>
      <GradientStop Color="Navy" Offset="1"/>
    </LinearGradientBrush>

    <LinearGradientBrush x:Key="PressedButtonBorder" StartPoint=".5,0" EndPoint=".5,1">
      <GradientStop Color="Navy" Offset="0"/>
      <GradientStop Color="Cyan" Offset="1"/>
    </LinearGradientBrush>

    <Style TargetType="{x:Type Button}">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate>
            <Grid>
              <Viewbox>
                <Canvas Width="{TemplateBinding Control.Width}" Height="{TemplateBinding Control.Height}">
                  <Ellipse x:Name="ButtonBody"
                      Fill="{TemplateBinding Control.Background}"
                      Width="{TemplateBinding Control.Width}"
                      Height="{TemplateBinding Control.Height}"
                      StrokeThickness="3"
                      Stroke="{DynamicResource NormalButtonBorder}" />
                </Canvas>
              </Viewbox>
              <ContentPresenter x:Name="ButtonContent" VerticalAlignment="Center"
HorizontalAlignment="Center" Content="{TemplateBinding Button.Content}"/>
            </Grid>
            <ControlTemplate.Triggers>
              <Trigger Property="Button.IsPressed" Value="True">
                <Setter TargetName="ButtonBody" Property="Stroke" Value="{DynamicResource PressedButtonBorder}"/>
                <Setter TargetName="ButtonContent" Property="Margin" Value="6,6,2,2"/>
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
  </Window.Resources>

  <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
    <Button Height="50" Width="100" Background="LightGreen" Margin="50">
      <TextBlock>
        <Span Foreground="Red">R</Span>
        <Span Foreground="Orange">a</Span>
        <Span Foreground="Yellow">i</Span>
        <Span Foreground="Green">n</Span>
        <Span Foreground="Cyan">b</Span>
        <Span Foreground="Blue">o</Span>
        <Span Foreground="Violet">w</Span>
      </TextBlock>

    </Button>
  </StackPanel>
</Window>

Leave a Reply

Your email address will not be published. Required fields are marked *