locked
How do you rotate an image in Canvas? A bug was found RRS feed

  • Question

  • I don't think you can rotate an image in Canvas using XAML.  I've done it using code, and I've done it in a Grid, but there's a bug it seems for Canvas.  Can anybody upload the markup?  One clue that there's a bug is that IntelliSense does not recognize RenderTransform or RotateTransform. (or rotatetransform rendertransform layouttransform in canvas

    Here is some of my code:

    <Window.Triggers>

            <EventTrigger RoutedEvent="Window.Loaded">

                <EventTrigger.Actions>

     

    <BeginStoryboard>

                        <Storyboard>

     

                         <!--has no effect (rotation does not work as you cannot get image to do a Render/Rotate in XAML in Canvas mode!--> 

                           

                       <!--    <DoubleAnimationUsingPath Storyboard.TargetName="image4"

                                                      Storyboard.TargetProperty="(Canvas.Left)"

                                                      PathGeometry="{StaticResource path}"

                                                      Duration="0:0:15" RepeatBehavior="Forever" Source="Angle" AutoReverse="True" />

                            -->

     

     

     

     

                            <DoubleAnimationUsingPath Storyboard.TargetName="image4"

                                                      Storyboard.TargetProperty="(Canvas.Left)"

                                                      PathGeometry="{StaticResource path}"

                                                      Duration="0:0:07" RepeatBehavior="Forever" Source="X" AutoReverse="True" />

     

                       <DoubleAnimationUsingPath Storyboard.TargetName="image4"

                                                      Storyboard.TargetProperty="(Canvas.Top)"

                                                      PathGeometry="{StaticResource path}"

                                                      Duration="0:0:07" RepeatBehavior="Forever"

                                                      Source="Y" AutoReverse="True" />

                            

                        </Storyboard>

     

                    </BeginStoryboard>

      

          

                </EventTrigger.Actions>

            </EventTrigger>

     

    //NOW IN XAML FURTHER DOWN, IN THE CANVAS SECTION—

     

    <Image Name="image4">

                <Image.Source>

                    <DrawingImage>

                        <DrawingImage.Drawing>

                            <GeometryDrawing Brush="LightSteelBlue">

                                <GeometryDrawing.Geometry>

                                    <GeometryGroup>

                                        <EllipseGeometry Center="10,10" RadiusX="9" RadiusY="4" />

                                        <EllipseGeometry Center="10,10" RadiusX="4" RadiusY="9" />

                                    </GeometryGroup>                                 

                                </GeometryDrawing.Geometry>

                                <GeometryDrawing.Pen>

                                    <Pen Thickness="1" Brush="Black" />

                                </GeometryDrawing.Pen>

                            </GeometryDrawing>

                        </DrawingImage.Drawing>

                    </DrawingImage>

                </Image.Source>

            </Image>

    Wednesday, November 25, 2009 5:27 PM

Answers

  • Hello RonConger09,
    you only need to make a small change to the storyboard code for image4 changing
    (TransformGroup.Children)[2] to
    (TransformGroup.Children)[3] as below:


    <BeginStoryboard>

                        <Storyboard Storyboard.TargetName="image4">

                                 <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image4" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(RotateTransform.Angle)">

    The resource "Storyboard1Rotate" is not being used in this snippet so the above change will need to be made to the "in place" code within the Windows.Triggers section.

    Each transform, Scale, Skew, Rotate etc are added to a collection, the TransformGroup. You reference items in this collection using an index notation within the xaml where the first item has the index 0 and the last n-1 where n is the number of items in the collection. In this case the xaml for image4 has the following transforms in your code:

    <Image Name="image4" RenderTransformOrigin="0.5,0.5" OpacityMask="#FF18DC2E" >
       <Image.RenderTransform>
        <TransformGroup>
         <ScaleTransform></ScaleTransform>
         <!--not used here-->
         <SkewTransform></SkewTransform>
         <!--not used here-->
         <TranslateTransform></TranslateTransform>
         <!--not used here-->
         <RotateTransform></RotateTransform>
        </TransformGroup>
       </Image.RenderTransform>

    Where the rotate transform is the 4th item whose index is 3 not 2 as you had in the storyboard.


    If you wanted to rotate the other four leaf clover image ("image") as it traces along the path for additional eye candy you could do this by adding the following code:
    Add a resource:

    <Storyboard  x:Key="imageRotation">
    			<DoubleAnimationUsingKeyFrames 
    							BeginTime="00:00:00" 
    							Storyboard.TargetName="image" 
    							Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)"
    							RepeatBehavior="Forever" 
    							>
    				<SplineDoubleKeyFrame KeyTime="00:00:01" Value="360" />
    			</DoubleAnimationUsingKeyFrames>
    		</Storyboard>

    And within the Image tag for "image" add the following Image.RenderTransorm:

    <Image Name="image" RenderTransformOrigin="0.5,0.5" >
    			<Image.RenderTransform>
    				<TransformGroup>
    					<RotateTransform></RotateTransform>
    				</TransformGroup>
    			</Image.RenderTransform>
    			<Image.Source>
    				<DrawingImage >
    					<DrawingImage.Drawing> Your code

    and finally under the EventTriggers add the storyboard reference:

    <EventTrigger RoutedEvent="Window.Loaded">
    			<EventTrigger.Actions>
    				<BeginStoryboard Storyboard="{StaticResource imageRotation}">
    					
    				</BeginStoryboard>

    Declaring storyboards as resources allows you to edit them in the animation workspace in Blend which I find very useful.

    I liked the Image4 design!

    regards

    Andrew

    • Marked as answer by RonConger09 Monday, November 30, 2009 7:36 PM
    Monday, November 30, 2009 4:55 PM

All replies

  •  Try:

    <Canvas>
    		<Image x:Name="image" Width="100" Height="100" Canvas.Left="161" Canvas.Top="137" RenderTransformOrigin="0.5,0.5">
    		           <Image.Source>
                    			<DrawingImage>
    					<DrawingImage.Drawing>
    						!--Your code 
    					</DrawingImage.Drawing>
    			         </DrawingImage>
    		            </Image.Source>
    			<Image.RenderTransform>
    				<TransformGroup>
    					<ScaleTransform/>
    					<SkewTransform/>
    					<RotateTransform/>
    					<TranslateTransform/>
    				</TransformGroup>
    			</Image.RenderTransform>
    		</Image>
    </Canvas>
    I placed the canvas in a grid.
    The Resources section looks like this

    <Window.Resources>
    		<Storyboard x:Key="Storyboard1">
    			<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)">
    				<SplineDoubleKeyFrame KeyTime="00:00:01" Value="56.31"/>
    				<SplineDoubleKeyFrame KeyTime="00:00:02" Value="188.13"/>
    				<SplineDoubleKeyFrame KeyTime="00:00:03" Value="254.055"/>
    				<SplineDoubleKeyFrame KeyTime="00:00:04" Value="360"/>
    			</DoubleAnimationUsingKeyFrames>
    		</Storyboard>
    	</Window.Resources>
    	<Window.Triggers>
    		<EventTrigger RoutedEvent="FrameworkElement.Loaded">
    			<BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>
    		</EventTrigger>
    </Window.Triggers></Window.Resources>
    This uses a transform group which includes a rotate transform. The syntax for specifying the storyboard target property within the transform group was a little hairy:

    Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)"


    regards

    Andrew
    Wednesday, November 25, 2009 9:42 PM
  • Hello Andrew Waters,

    I appreciate your help, but despite your suggestion I could not get the rotate feature to work (I can get translation along a path however, which I find more useful anyway). 

    Below is the code--if you see anything strange please let me know.

    Since this rotation is for me just eye candy and not essential to my program, I will simply abandon this attempt at rotation unless I hear back from you within a few days.

    XAML is not strongly typed, so the below compiles but the image "image4" does not rotate.

    RC


    <Window x:Class="WpfApplication1.Window2"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="Window2" Height="381.6" Width="521.6">

        <Window.Resources>

     

            <PathGeometry x:Key="path">

                <PathFigure IsClosed="False">

                    <ArcSegment Point="100,200" Size="15,10" SweepDirection="Clockwise"></ArcSegment>

                    <ArcSegment Point="400,50" Size="5,5" ></ArcSegment>

                </PathFigure>

            </PathGeometry>

            <Storyboard x:Key="Storyboard1Rotate">

                <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image4" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)">

                    <SplineDoubleKeyFrame KeyTime="00:00:01" Value="56.31" />

                    <SplineDoubleKeyFrame KeyTime="00:00:02" Value="188.13" />

                    <SplineDoubleKeyFrame KeyTime="00:00:03" Value="254.055" />

                    <SplineDoubleKeyFrame KeyTime="00:00:04" Value="360" />

                </DoubleAnimationUsingKeyFrames>

            </Storyboard>

        </Window.Resources>

       

        <Window.Triggers>

            <EventTrigger RoutedEvent="Window.Loaded">

                <EventTrigger.Actions>

                    <BeginStoryboard>

                        <Storyboard x:Name="myFirstStoryboard" Timeline.DesiredFrameRate="60">

                            <DoubleAnimationUsingPath Storyboard.TargetName="image"

                                          Storyboard.TargetProperty="(Canvas.Left)"

                                         PathGeometry="{StaticResource path}"

                                          Duration="0:0:5" Source="X" AutoReverse="True" />

                            <DoubleAnimationUsingPath Storyboard.TargetName="image"

                                          Storyboard.TargetProperty="(Canvas.Top)"

                                         PathGeometry="{StaticResource path}"

                                          Duration="0:0:5" Source="Y" AutoReverse="True" />

                        </Storyboard>

                    </BeginStoryboard>

            

                    <BeginStoryboard>

                        <Storyboard Timeline.DesiredFrameRate="30">

                            <DoubleAnimationUsingPath Storyboard.TargetName="image2"

                                          Storyboard.TargetProperty="(Canvas.Left)"

                                         PathGeometry="{StaticResource path}"

                                          Duration="0:0:10" RepeatBehavior="Forever" Source="X" AutoReverse="True" />

                            <DoubleAnimationUsingPath Storyboard.TargetName="image2"

                                          Storyboard.TargetProperty="(Canvas.Top)"

                                         PathGeometry="{StaticResource path}"

                                          Duration="0:0:10" RepeatBehavior="Forever" Source="Y" AutoReverse="True" />

                        </Storyboard>

                    </BeginStoryboard>

                   

     

                 

     

                    <BeginStoryboard>

                        <Storyboard Storyboard.TargetName="image4">

                                 <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image4" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)">

                                    <SplineDoubleKeyFrame KeyTime="00:00:01" Value="56.31" />

                                    <SplineDoubleKeyFrame KeyTime="00:00:02" Value="188.13" />

                                    <SplineDoubleKeyFrame KeyTime="00:00:03" Value="254.055" />

                                    <SplineDoubleKeyFrame KeyTime="00:00:04" Value="360" />

                                </DoubleAnimationUsingKeyFrames>

                            </Storyboard>

     

                    </BeginStoryboard>

     

     

                </EventTrigger.Actions>

            </EventTrigger>

                  

        </Window.Triggers>

        <Canvas Margin="5">

            <Path Stroke="Red" StrokeThickness="1" Data="{StaticResource path}" Canvas.Top="10" Canvas.Left="10">

            </Path>

            <Image Name="image">

                <Image.Source>

                    <DrawingImage>

                        <DrawingImage.Drawing>

                            <GeometryDrawing Brush="LightSteelBlue">

                                <GeometryDrawing.Geometry>

                                    <GeometryGroup>

                                        <EllipseGeometry Center="10,10" RadiusX="9" RadiusY="4" />

                                        <EllipseGeometry Center="10,10" RadiusX="4" RadiusY="9" />

                                    </GeometryGroup>                                 

                                </GeometryDrawing.Geometry>

                                <GeometryDrawing.Pen>

                                    <Pen Thickness="1" Brush="Black" />

                                </GeometryDrawing.Pen>

                            </GeometryDrawing>

                        </DrawingImage.Drawing>

                    </DrawingImage>

                </Image.Source>

            </Image>

           

            <Image Source="{x:Null}" Stretch="None" x:Name="image2" ></Image>

            <Image Source="{x:Null}" Stretch="None" x:Name="image3" ></Image>

           

            <Image Name="image4" RenderTransformOrigin="0.5,0.5" >

                <Image.RenderTransform>

                    <TransformGroup>

                        <ScaleTransform></ScaleTransform>

                        <!--not used here-->

                        <SkewTransform></SkewTransform>

                        <!--not used here-->

                        <TranslateTransform></TranslateTransform>

                        <!--not used here-->

                        <RotateTransform></RotateTransform>

                    </TransformGroup>

                </Image.RenderTransform>

                <Image.Source>

                   

                    <DrawingImage> 

                      

                        <DrawingImage.Drawing>

                            <GeometryDrawing Brush="OrangeRed">

                                <GeometryDrawing.Geometry>

                                   

                                    <GeometryGroup>

                                        <EllipseGeometry Center="10,5" RadiusX="6" RadiusY="10" />

                                        <EllipseGeometry Center="10,20" RadiusX="12" RadiusY="20" />

                                        <EllipseGeometry Center="10,35" RadiusX="6" RadiusY="10" />

                                        <LineGeometry StartPoint="0,10" EndPoint="10,20"></LineGeometry>

                                        <LineGeometry StartPoint="0,20" EndPoint="10,20"></LineGeometry>

                                        <LineGeometry StartPoint="0,30" EndPoint="10,20"></LineGeometry>

                                        <LineGeometry StartPoint="20,10" EndPoint="10,20"></LineGeometry>

                                        <LineGeometry StartPoint="20,20" EndPoint="10,20"></LineGeometry>

                                        <LineGeometry StartPoint="20,30" EndPoint="10,20"></LineGeometry>

                                    </GeometryGroup>

                                </GeometryDrawing.Geometry>

                                <GeometryDrawing.Pen>

                                    <Pen Thickness="2" Brush="Orange" />

                                </GeometryDrawing.Pen>

                            </GeometryDrawing>

                          

                        </DrawingImage.Drawing>

                    </DrawingImage>

                </Image.Source>

     

            </Image>

            

           

        </Canvas>

       

    </Window>

     

     

    Friday, November 27, 2009 8:05 PM
  • Hello RonConger09,
    you only need to make a small change to the storyboard code for image4 changing
    (TransformGroup.Children)[2] to
    (TransformGroup.Children)[3] as below:


    <BeginStoryboard>

                        <Storyboard Storyboard.TargetName="image4">

                                 <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image4" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(RotateTransform.Angle)">

    The resource "Storyboard1Rotate" is not being used in this snippet so the above change will need to be made to the "in place" code within the Windows.Triggers section.

    Each transform, Scale, Skew, Rotate etc are added to a collection, the TransformGroup. You reference items in this collection using an index notation within the xaml where the first item has the index 0 and the last n-1 where n is the number of items in the collection. In this case the xaml for image4 has the following transforms in your code:

    <Image Name="image4" RenderTransformOrigin="0.5,0.5" OpacityMask="#FF18DC2E" >
       <Image.RenderTransform>
        <TransformGroup>
         <ScaleTransform></ScaleTransform>
         <!--not used here-->
         <SkewTransform></SkewTransform>
         <!--not used here-->
         <TranslateTransform></TranslateTransform>
         <!--not used here-->
         <RotateTransform></RotateTransform>
        </TransformGroup>
       </Image.RenderTransform>

    Where the rotate transform is the 4th item whose index is 3 not 2 as you had in the storyboard.


    If you wanted to rotate the other four leaf clover image ("image") as it traces along the path for additional eye candy you could do this by adding the following code:
    Add a resource:

    <Storyboard  x:Key="imageRotation">
    			<DoubleAnimationUsingKeyFrames 
    							BeginTime="00:00:00" 
    							Storyboard.TargetName="image" 
    							Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)"
    							RepeatBehavior="Forever" 
    							>
    				<SplineDoubleKeyFrame KeyTime="00:00:01" Value="360" />
    			</DoubleAnimationUsingKeyFrames>
    		</Storyboard>

    And within the Image tag for "image" add the following Image.RenderTransorm:

    <Image Name="image" RenderTransformOrigin="0.5,0.5" >
    			<Image.RenderTransform>
    				<TransformGroup>
    					<RotateTransform></RotateTransform>
    				</TransformGroup>
    			</Image.RenderTransform>
    			<Image.Source>
    				<DrawingImage >
    					<DrawingImage.Drawing> Your code

    and finally under the EventTriggers add the storyboard reference:

    <EventTrigger RoutedEvent="Window.Loaded">
    			<EventTrigger.Actions>
    				<BeginStoryboard Storyboard="{StaticResource imageRotation}">
    					
    				</BeginStoryboard>

    Declaring storyboards as resources allows you to edit them in the animation workspace in Blend which I find very useful.

    I liked the Image4 design!

    regards

    Andrew

    • Marked as answer by RonConger09 Monday, November 30, 2009 7:36 PM
    Monday, November 30, 2009 4:55 PM
  • Thanks Andrew... that Image4 design was novel...some kind of Zulu warrior shield I must have been thinking of.

    Using your expert advice I solved it.

    BTW I found that using code behind and XAML markup you can easily change the RepeatBehavior property as follows:

    using Code, but only if Storyboard is not a "key": 

      myFirstStoryboard.RepeatBehavior = new System.Windows.Media.Animation.RepeatBehavior(2.0);

    using XAML (if the StoryBoard is a "key") add this attribute:

    RepeatBehavior

     

    ="10x" 
     
    Or something similar (some multiple of x) that makes the animation stop after a set time; you have to run the animation and see what looks good.

    Monday, November 30, 2009 7:36 PM
  • Glad it worked. Good point about code usage.

    Tuesday, December 1, 2009 11:53 AM