Search code examples
wpfxamlrotatetransformrendertransformlayouttransform

Why LayoutTransform do not change vertice coordinates (x1,y1) on rotation


I have a canvas which contains shapes (path) where i bind angle with rotatetransform in layout transform.

I generate MouseRightButtonUp on canvas when mouse is over the shape (generated by my path) then right click i rotate by 90 degree using Layout transform.

But it behaves like Render transform because the my binded canvas.left and canvas.top do not updates/change after rotation on right click of mouse over shape whereas angle gets changed. my code is here :

<Canvas Name="OuterCanvas" Background="Green"  Height="700" Width="1000"  >
    <ItemsControl  AllowDrop="True"  x:Name="itemsCtrl" ItemsSource="{Binding ShapesCollection,Mode=TwoWay}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas ClipToBounds="True" IsItemsHost="True"  Height="700" Width="1000" Background="Transparent" x:Name="dragCanvas">
                    <i:Interaction.Triggers>                                          
                        <i:EventTrigger EventName="MouseRightButtonUp">
                            <ie:CallMethodAction MethodName="MouseRightButtonUpEventHandler" TargetObject="{Binding}" />
                        </i:EventTrigger>
                    </i:Interaction.Triggers>                                          
                </Canvas>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Path  x:Name="im" Canvas.Left="{Binding Path=Canvas_Left , Mode=TwoWay}"
                      Canvas.Top="{Binding Path=Canvas_Top , Mode=TwoWay}"
                      Fill="{Binding Fill}"  Stroke="{Binding Stroke}"
                      StrokeThickness="{Binding StrokeThickness}" 
                      Data="{Binding Path=Data,Mode=TwoWay}">                                       
                    <Path.LayoutTransform>
                        <RotateTransform Angle="{Binding Path=Angle , Mode=TwoWay}"/>
                    </Path.LayoutTransform>                                             
                </Path>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Canvas.Left" Value="{Binding Path=Canvas_Left , Mode=TwoWay}" />
                <Setter Property="Canvas.Top" Value="{Binding Path=Canvas_Top , Mode=TwoWay}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>
</Canvas>

the invoked method for rotation in viewmodel is:

   public void MouseRightButtonUpEventHandler(object sender, MouseButtonEventArgs e)
    {
        e.Handled = true;
        ElementBeingDragged = e.Source as UIElement;
        if (ElementBeingDragged is System.Windows.Shapes.Path)
            if (ElementBeingDragged != null)
            {
                if (ElementBeingDragged.AllowDrop)
                {
                    var rotateTransform = ((System.Windows.Shapes.Path)ElementBeingDragged).LayoutTransform as RotateTransform;
                    if (rotateTransform == null)
                    {
                        (e.Source as FrameworkElement).LayoutTransform = new RotateTransform();                            
                    }
                    ((System.Windows.Shapes.Path)ElementBeingDragged).LayoutTransform = rotateTransform;
                    ((System.Windows.Shapes.Path)ElementBeingDragged).RenderTransformOrigin = new Point(0.5, 0.5);
                    rotateTransform.Angle += 90;
                }
                 ((System.Windows.Shapes.Path)ElementBeingDragged).UpdateLayout();//.LayoutUpdated();
                isDragInProgress = false;
                Mouse.Capture(null);
            }

    }

Why Canvas.Left and Canvas.Top never gets updated even after the change in the position of shapeon change of the angle? (lets say rectangle has A(x1,y1) B(x2,y2) , c(x3,y3) D(x4,y4) then after 90 degree rotation it must be A(x2,y2) B(x3,y3) , c(x4,y4) D(x1,y1) why the in my Model below Canvas.Left and Canvas.Top never updates ?

   public class Shapes :ICloneable
    { private double angle;
        public double Angle
        {
            get { return angle; }//Updates on rotation
            set
            {
                angle = value;
                RaisePropertyChanged("Angle");
            }
        }
        public double canvas_Top { get; set; }
        public double Canvas_Top
        {
            get { return canvas_Top; }//Never updates on rotation
            set
            {
                canvas_Top = value;
                RaisePropertyChanged("Canvas_Top");
            }
        }
        private double canvas_Left;
        public double Canvas_Left
        {
            get { return canvas_Left; } //Never updates on rotation
            set
            {
                canvas_Left = value;
                RaisePropertyChanged("Canvas_Left");
            }
        }
    }

This behavior is expected in Rendertransform but why in this case LayoutTransform behave like Rendertransform because i have used LayOutTranform


Solution

  • A transform does not change the underlying coordinates or Control Properties. Think of it like applying a mask over the base Properties that calculates new positions or values but does not change the original.

    For example: If i have a square with a side length of 2. I then apply a Scaling Tranform of 2. The original side length remains =2. The transform will calculate a new side length of 4 and display the square at a size of 4. If i remove the transform, the square would be the original size of 2. To Compare to your 90 degree rotation example, While you are correct that the rendered values of x1,y1 and x2,y2 change, the underlying values do not. I.e. Visually you see them change, but the transform is what makes that visual change.

    The difference between RenderTransform .vs. LayoutTransform primarily happens to WHEN these calculations happen (i.e. when do i multiply my square sides by 2, or rotate my rectangle by 90 degrees). Both will still not adjust the origin of your other properties. Look Here for a good explanation. (Im sure there a more differences; but this is where i believe the confusion is happening)

    If you want to actually adjust the Canvas.Top or Canvas.Left properties from a transform, you would need to apply the transform to those values and then set the Properties with the calculated value from your Transform.