How do I Bind a WPF Ellipse's Height to its own Width?

Curtis picture Curtis · Mar 19, 2015 · Viewed 7k times · Source

I have an ellipse drawn inside a Grid.Row and Grid.Column. The Row is always taller than the Column is wide.

I want to draw an ellipse that fills the width of the grid column and who's height makes it a perfect circle.

I also want to draw a single digit number exactly in the center of the above ellipse. Basically ending up with a circle that has a number centered inside it.

I can easily set HorizontalAlignment="Stretch" on my Ellipse and on the TextBlock containing the number. This takes care of the width for me. However, how do I get the Height of the Ellipse and TextBlock to always match its Width, even when the Grid.Column width changes?

Here's some XAML to illustrate this. In the XAML below, I want the hard coded '63' to be based on the Grid.Column width, or the Width feild of the ellipse:

    <Ellipse Grid.Row="1" Grid.Column="0" HorizontalAlignment="Stretch" Height="63" Stroke="Black" StrokeThickness="3" VerticalAlignment="Top"/>
    <TextBlock Grid.Row="1" Grid.Column="0" Width="63" Height="63" VerticalAlignment="Top" Text="1" TextAlignment="Center" FontSize="42" FontWeight="Bold"/>

Thanks for all your help. I ended up using Herdo's answer. Just set HorizontalAlignment to Stretch and then bind the height to the actual width of the ellipse. I did this same thing to the ellipse and to the text block:

    <Ellipse HorizontalAlignment="Stretch" Height="{Binding ActualWidth, RelativeSource={RelativeSource Self}}"/>
    <TextBlock HorizontalAlignment="Stretch" Height="{Binding ActualWidth, RelativeSource={RelativeSource Self}}"/>

Answer

Herdo picture Herdo · Mar 19, 2015

Assuming you have a Grid containing the Ellipse, you can use the ActualWidth property, and keeping it stretched, without setting the Width property - allowing you to use the Ellipse without any reference to the parent container:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/> <!-- Or whatever width -->
    </Grid.ColumnDefinitions>

    <Ellipse Grid.Column="0"
             HorizontalAlignment="Stretch"
             Height="{Binding ActualWidth, RelativeSource={RelativeSource Self}}"/>
</Grid>

Please take into account the remarks for the ActualWidth property on MSDN:

Because ActualWidth is a calculated value, you should be aware that there could be multiple or incremental reported changes to it as a result of various operations by the layout system. The layout system may be calculating required measure space for child elements, constraints by the parent element, and so on.

Therefore, the following example code...

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="30"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <Ellipse Grid.Row="1"
             Grid.Column="1"
             HorizontalAlignment="Stretch"
             Fill="Red"
             Height="{Binding ActualWidth, RelativeSource={RelativeSource Self}}"/>
</Grid>

...will result into this behavior (the width/height would update every time, the container - the Grid in this case - changes its layout):

enter image description here