38

I'm learning WPF and can't figure out how to enfore my buttons to take a square shape.

Here is my XAML Markup:

<Window x:Class="Example"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="368" Width="333">
  <Window.Resources>
    <Style x:Key="ToggleStyle" BasedOn="{StaticResource {x:Type ToggleButton}}"
                            TargetType="{x:Type RadioButton}">
    </Style>
  </Window.Resources>
  <RadioButton Style="{StaticResource ToggleStyle}">
        Very very long text
  </RadioButton>
</Window>

Specifying explicit values for Width and Height attributes seems like a wrong idea - the button should calculate its dimensions based on its contents automagically, but keep its width and height equal. Is this possible?

Gart
  • 2,297
  • 1
  • 28
  • 36
  • http://stackoverflow.com/questions/288954/how-do-i-keep-aspect-ratio-on-scalable-scrollable-content-in-wpf – Mangesh Dec 07 '14 at 18:15

5 Answers5

56

Try this - it seems to work in Kaxaml:

<Button 
    MinWidth="{Binding ActualHeight, RelativeSource={RelativeSource Self}}" 
    MinHeight="{Binding ActualWidth, RelativeSource={RelativeSource Self}}">
  Some content
</Button>

(To test, I put a TextBox inside the button, because that's an easy way to change content size without re-parsing the Xaml.)

Edit: sorry, should probably have specified it as a style to match your example:

<Style TargetType="Button" x:Key="SquareButton">
  <Setter Property="MinWidth" Value="{Binding ActualHeight, RelativeSource={RelativeSource Self}}" />
  <Setter Property="MinHeight" Value="{Binding ActualWidth, RelativeSource={RelativeSource Self}}" />
</Style>
Dan Puzey
  • 33,626
  • 4
  • 73
  • 96
  • There is any way to do same but instead of min, for max? – Black Cid Apr 13 '15 at 10:42
  • You should ask a separate question; I'm not sure what you'd be trying to achieve. This snippet forces a button to be square that surrounds its contents; what would you be trying to achieve? – Dan Puzey Apr 13 '15 at 13:19
  • I have written the answer: http://stackoverflow.com/questions/29620938/windows-phone-xaml-force-square-proportioned-container-aspectratio-11 – Black Cid Apr 14 '15 at 06:52
  • 5
    The only problem with this solution is that the control can grow, but it cannot shrink. So if the window is resized bigger the control will get bigger, but when the window shrinks, the control will remain the larger size. – bwing Mar 24 '18 at 18:12
  • Yes and it also breaks the designer, if you use this and resize the window in the designer, I wouldn't recommend this solution. – Andre May 16 '19 at 11:01
5

The currently accepted answer cannot grow AND shrink. I think I found a better approach, by defining a custom style with a rectangle (stretched uniformly).

<Style x:Key="SquareButton" TargetType="Button">
    <Setter Property="Foreground" Value="White"/>
    <Setter Property="Background" Value="#3a3a3a" />
    <Setter Property="BorderBrush" Value="#5a5a5a"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">

                <Border HorizontalAlignment="Center">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="auto"/>
                        </Grid.ColumnDefinitions>
                        <Rectangle Stretch="Uniform"
                                         Stroke="{TemplateBinding BorderBrush}"
                                         StrokeThickness="4"
                                         Margin="0" 
                                         Fill="{TemplateBinding Background}" 
                                         Panel.ZIndex="1"
                                         />
                        <ContentPresenter Margin="10" 
                           HorizontalAlignment="Center" 
                           VerticalAlignment="Center" 
                           Panel.ZIndex="2" />
                    </Grid>
                    </Border>

            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="Background" Value="#4a4a4a"/>
        </Trigger>
    </Style.Triggers>
</Style>

Btw, you can also create a perfect round button this way. Just replace Rectangle with Ellipse.

yvan vander sanden
  • 955
  • 1
  • 12
  • 13
4

I think you want to bind button's width to its height, like this:

<Button Name="myButton"
Width="{Binding ElementName=myButton, Path=Height}"
Height="100">
Button Text
</Button>
n535
  • 4,983
  • 4
  • 23
  • 28
  • 5
    I think Gart wants it to still autosize to content, which is slightly trickier to accomplish. Also, rather than using `ElementName`, you could use `RelativeSource={RelativeSource Self}`, which is more easily portable. – Dan Puzey Jun 05 '10 at 22:20
3

@Dan Pruzey's answer was good, but did not shrink the square if the window was downsized. What I found to work best was to set the height to auto and the width to that height:

<Button Height="Auto" Width="{Binding ActualHeight, RelativeSource={RelativeSource Self}}"/>

This kept the button a square when sizing my window bigger and smaller. Hope this helps someone.

Ethan Shoe
  • 466
  • 1
  • 7
  • 20
1

I found a simpler solution for the case where you want the button to expand and shrink, tipically when its text changes:

   <RadioButton  Style="{StaticResource ToggleStyle2}" 
           HorizontalAlignment="Center" VerticalAlignment="Center"
           HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
           Width="{Binding Path=ActualWidth, ElementName=txtblck_innerText }"
           Height="{Binding Path=ActualWidth, ElementName=txtblck_innerText }">
           
            
           <TextBlock x:Name="txtblck_innerText" 
                 MinWidth="{Binding ActualHeight, RelativeSource={RelativeSource Self}}" >
                Very very long text.........
           </TextBlock>
    </RadioButton>

This solution above applies when the size of the button is imposed by its content (comes from inside) as stated in the question.

However, in case you want a square button whose size is imposed by the place where it is going to be (comes from outside), for instance, the size of the grid cell that contains the button, a solution could be:

     <RadioButton Style="{StaticResource ToggleStyle2}"
          HorizontalAlignment="Center" VerticalAlignment="Center"
          HorizontalContentAlignment="Center" VerticalContentAlignment="Center">
         <Viewbox Stretch="Uniform">
            <Border Width="20" Height="20">
               <Viewbox Stretch="Uniform">  
                  <TextBlock x:Name="txtblck_innerText">
                         Very very long text...........
                  </TextBlock>                       
               </Viewbox>
            </Border>
         </Viewbox>  
     </RadioButton>
Amo Robb
  • 810
  • 5
  • 11