1
votes

I have a canvas which has many images appearing dynamically on it and i used items control for it. I had to drag drop and rotate(on mouse right button click) those images and update new locations and rotation angle back to source code (VM and Model).

I am able to display on my screen images and my canvas.left and canvas.right are getting updated for new locations in source when i do drag and drop of Images on canvas. The problem is when i rotate image, The image gets rotated but the new Angle in source is not updated in my source (VModel), I mean this property never gets called when i rotate the image.

 public double Angle {
            get { return angle; }
            set  //NEVER GETS CALLED ON ROTATION
            {
                angle = value;
                RaisePropertyChanged("Angle");
            }
        }

It is binded correctly because when i display the images dynamically on canvas, they are displayed with the same angle which i have provided them from source. Earlier i suspected Mode to not set of TwoWay binding. Even i set to TwoWay it do not work. I also added UpdateSourceTrigger=PropertyChanged but still do not work . Why angle is never updated on rotating the image whereas canvas.left and canvas.top are updated.

Here is my XAML :

                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <dd:DragCanvas Height="800" Width="1000" Background="Black" x:Name="dragCanvas" 
                         AllowDragging="True" 
                         />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Image Source="{Binding Path=path}" >
                        </Image>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
                <ItemsControl.ItemContainerStyle>
                    <Style TargetType="ContentPresenter">
                        <Setter Property="Canvas.Left" Value="{Binding Path=Canvas_Left , Mode=TwoWay}" />  //It is updated
                        <Setter Property="Canvas.Top" Value="{Binding Path=Canvas_Top , Mode=TwoWay}" /> //It is Updated
                        <Setter Property="RenderTransform">  //It never updated from target to source but source to target is updated
                            <Setter.Value>
                                <RotateTransform Angle="{Binding Path=Angle ,Mode=TwoWay}"/>
                            </Setter.Value>
                        </Setter>                                
                    </Style>
                </ItemsControl.ItemContainerStyle>
            </ItemsControl>

Here is where i rotate on mouse right button click(inside dd:DragCanvas )

   public class DragCanvas : Canvas
    {

       protected override void OnMouseRightButtonUp(MouseButtonEventArgs e)  //HERE IS WHERE I ROTATE by 90 degree
        {
            base.OnMouseRightButtonUp(e);
            ElementBeingDragged = e.Source as UIElement;
            var rotateTransform = ElementBeingDragged.RenderTransform as RotateTransform;
            if (rotateTransform == null)
            {
                rotateTransform = new RotateTransform();
                ElementBeingDragged.RenderTransform = rotateTransform;
                ElementBeingDragged.RenderTransformOrigin = new Point(0.5, 0.5);
            }
            rotateTransform.Angle += 90;
            ElementBeingDragged.UpdateLayout();
        }
    }

How to update angle property (target to source), such that each time i rotate the Image i have set part of the property Angle called

public double Angle {
            get { return angle; }
            set  //It must be called when i rotate the image on right mouse click
            {
                angle = value;
                RaisePropertyChanged("Angle");
            }
        }
1
Are you saying that RotateTransform.Angle never updates your viewmodel Angle property?15ee8f99-57ff-4f92-890c-b56153
By the way, you're setting traps for yourself by making your backing fields public and not prefixing them with underscores. With the help of intellisense, one day you'll end up assigning a value to canvas_Top and wondering why PropertyChanged is never raised.15ee8f99-57ff-4f92-890c-b56153
You're binding to LayoutTransform but updating RenderTransform. LayoutTransform gets applied while calculating Layout, while RenderTransform gets applied at the time of rendering.Rachel
As a note, you don't have to call ElementBeingDragged.UpdateLayout(). That's entirely redundant.Clemens
@EdPlunkett yes he means same .user3085082

1 Answers

1
votes

You're binding to LayoutTransform but updating RenderTransform. LayoutTransform gets applied while calculating Layout, while RenderTransform gets applied at the time of rendering.

Change your binding to RenderTransform and it should work.

Edit : Just realized when switching to using RenderTransform, you need to apply the transform to the Image, not the ContentPresenter wrapping the image.

<ItemsControl.ItemTemplate>
    <DataTemplate>
        <Image Source="{Binding Path=path}" >
            <Image.ItemContainerStyle>
                <Style TargetType="ContentPresenter">
                    <Setter Property="RenderTransform">
                        <Setter.Value>
                            <RotateTransform Angle="{Binding Path=Angle ,Mode=TwoWay}"/>
                        </Setter.Value>
                    </Setter>                                
            </Style>
            </Image.Style>
        </Image>
    </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>

If you apply a transformation during the Layout pass, it will adjust other items within the Layout to fit as well. So applying a transform to the ContentPresenter that wraps the Image during Layout will also calculate that it needs to apply the same transform to the inside Image.

But if it's applied during Rendering, the only the ContentPresenter gets the transform applied and the child Image remains unchanged because the initial Layout pass decided it didn't need any modifications.