Search code examples
wpfxamlrendertransform

Path RenderTransform not equal to Border around it with RenderTransform?


I had expected the following two pieces of XAML to produce the same output. However, the RenderTransform on the Path uses some funky rotation point that I don't understand. Can someone explain to me why these two pieces of XAML are not equivalent?

<Window x:Class="CenterPathTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Canvas>
        <Canvas.RenderTransform>
            <TranslateTransform X="50" Y="50"/>
        </Canvas.RenderTransform>
        <Border Width="100" Height="200">
            <Border.RenderTransform>
                <TransformGroup>
                    <TranslateTransform X="70" Y="-100"/>
                    <RotateTransform Angle="90"/>
                </TransformGroup>
            </Border.RenderTransform>
            <Path Width="100" Height="200" Stretch="Uniform"
                Data="M 0,20M 20,0M 6.04,4.51 C6.04,4.51 7.54,3 7.54,3 7.54,3 14.5,10 14.5,10 14.5,10 7.54,17 7.54,17 7.54,17 6.04,15.48 6.04,15.48 6.04,15.48 11.5,10 11.5,10 11.5,10 6.04,4.51 6.04,4.51 z" />
        </Border>
    </Canvas>
</Window>

I consider the behavior on this one following to be incorrect:

<Window x:Class="CenterPathTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Canvas>
        <Canvas.RenderTransform>
            <TranslateTransform X="50" Y="50"/>
        </Canvas.RenderTransform>
        <Path Width="100" Height="200" Stretch="Uniform"
            Data="M 0,20M 20,0M 6.04,4.51 C6.04,4.51 7.54,3 7.54,3 7.54,3 14.5,10 14.5,10 14.5,10 7.54,17 7.54,17 7.54,17 6.04,15.48 6.04,15.48 6.04,15.48 11.5,10 11.5,10 11.5,10 6.04,4.51 6.04,4.51 z">
            <Path.RenderTransform>
                <TransformGroup>
                    <TranslateTransform X="70" Y="-100"/>
                    <RotateTransform Angle="90"/>
                </TransformGroup>
            </Path.RenderTransform>
        </Path>
    </Canvas>
</Window>

Solution

  • You are correct about the rotation point being related to the Stretch property on your second example. To test this, you can change your XAML so that both examples have Stretch="None", and you can see that they perfectly overlap.

    Your second example is a good example on how not to do it. :) When you have a path object and are stretching it by some unknown amount, your default RenderTransformOrigin is also stretched/moved.

    The first example works as expected, because you are doing the TranslateTransform and the RotateTransform on the Border object which hasn't been stretched or scaled. The Path object inside the border is then free to scale up to the needed dimensions without being adversely affected by the transforms that are occurring on the parent object (the Border).

    In order to get your second example to behave identically to the first, you need to figure out the exact scale factor that occurs when the Path is stretched to fit your 100x200 size bounds. Then you would have to use that number to either calculate a new RenderTransformOrigin or to calculate new X and Y values for the TranslateTransform.

    ..or..

    Change the Data in the second Path object to draw the chevron at the full 'stretched' size initially.

    Given the complexity of either of those solutions, leaving the Path inside the Border object is by far the easiest route.