3

I'm trying to center a Path so that its origin (0, 0) is located at the bottom, center of its container. Assume that the container is a Grid.


Example:

Tail of arrow is at the center-bottom of the box

Note: the tail of the arrow is at the origin (0, 0). The tail is centered horizontally but the overall arrow is skewed to the left. This is what I want to achieve regardless of which direction the arrow is pointing.


This needs to work for paths where the x and y coordinates are positive, negative, or a mixture of both.

How can this be done via XAML with the least markup?

devuxer
  • 41,681
  • 47
  • 180
  • 292

3 Answers3

3

Here is what I have been using. Just draw your path wherever you want and afterwards translate it to the desired starting point. You can use Bindings to center it within the grid. This allows to place your geometry wherever you want within your grid.

<Grid>
    <Path Stroke="Black"
          StrokeThickness="1">
        <Path.Data>
            <PathGeometry>
                <!-- Your path geomrtry -->
            </PathGeometry>
        </Path.Data>
        <Path.RenderTransform>
            <TranslateTransform Y="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid}, Path=ActualHeight, Converter={StaticResource widthAndHeightDivider}}"
                                X="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid}, Path=ActualWidth, Converter={StaticResource widthAndHeightDivider}}"/>
        </Path.RenderTransform>
    </path>
</Grid>

And having the following converter, which divides the ActualWidth of the grid by to to get it centered:

public class WidthAndHeightDivider : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        double d = (double)value / 2.0;
        return d;
    }
}

I hope this helps!

Ecuashungo
  • 78
  • 12
2

Here's what I ended up going with. Seems to work, but if there's a cleaner way to do this, I'd love to hear it:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Path Grid.Column="1"
          HorizontalAlignment="Left"
          VerticalAlignment="Bottom"
          StrokeThickness="1"
          Data="{Binding PathGeometry}" />
</Grid>
devuxer
  • 41,681
  • 47
  • 180
  • 292
  • Didn't this left align the path? – NestorArturo Mar 06 '12 at 19:11
  • The column definitions divide the grid in half, then the path gets left aligned within the right half. The really confusing part is that what gets aligned is not the whole path, only the part of the path where the (x, y) values are positive. – devuxer Mar 06 '12 at 20:09
  • 1
    At first I was going to suggest you don't do this and instead use the render transform like the other answer, but the more I thought about how panel layouts actually work and how the transforms work and how this has the added advantage of not knowing, or caring what the size of the path is, the more I realized this is actually quite clever! I may have to crib this idea for my own in a few cases! :) – Mark A. Donohoe Dec 01 '20 at 16:47
  • 1
    BTW, it's not that 'only the positive parts' get aligned. It's for layout purposes, the left and top 'edges' of a path are along the y and x axes respectively. The width and height however are determined by the lower-most and right-most portions of the drawn path. For instance, if you wanted a 20-dia circle at the center of a 100x100 area, if you didn't set the width manually, you'd end up with a control that's 60x60 with the circle at the bottom right. Your trick negates the need to worry about the size at all which is why it's actually quite clever! – Mark A. Donohoe Dec 01 '20 at 16:51
0

Well... the position en in the bottom-middle depends on the container. Try something like this:

<Grid>
  <Path Stroke="Black"
        StrokeThickness="1"
        VerticalAlignment="Bottom"
        HorizontalAlignment="Center"
        Data="M 0,0 L -50,-70 L -50,-80" />
</Grid>
NestorArturo
  • 2,476
  • 1
  • 18
  • 21
  • This was the first thing I tried. It only works if the arrow is pointing NW (as in your example) or SW. I need it to also work if the arrow is pointing NE or SE. And I can't reverse the arrow so that the head of the arrow is at (0, 0), i.e., the tail must be at (0, 0). – devuxer Mar 05 '12 at 21:23