locked
I want to target the Left and Top properties relative to the Canvas for animating a rectangle ...

    Question

  • Hi,

    I tried this but I can't figure out how to set the second argument to Storyboard.SetTargetProperty(). My rectangle "rect1" is inside the root element which is a canvas. I have tried many different ways to set the property string based on MSDN docs but I can't figure it out. Keep getting "Cannot resolve TargetProperty (<whatever>) on specified object".

    My latest attempt uses ...

    TranslateTransform trans = new TranslateTransform();rect1.RenderTransform = trans;

    to try and get a reference to the X and Y coordinates of the Rectangle.

    Duration duration = new Duration(TimeSpan.FromSeconds(5));
    
                DoubleAnimation anim1 = new DoubleAnimation();
                DoubleAnimation anim2 = new DoubleAnimation();
    
    
                anim1.Duration = duration;
                anim2.Duration = duration;
    
    
                Storyboard sb = new Storyboard();
    
                sb.Duration = duration;
    
                sb.Children.Add(anim1);
                sb.Children.Add(anim2);
    
                Storyboard.SetTarget(anim1, rect1);
                Storyboard.SetTarget(anim2, rect1);
    
                TranslateTransform trans = new TranslateTransform();
                rect1.RenderTransform = trans;
    
                Storyboard.SetTargetProperty(anim1, "(trans.Y)");
                Storyboard.SetTargetProperty(anim2, "(trans.X)");
    
                anim1.To = 0;
                anim2.To = 500;
    
    
                // Make the Storyboard a resource.
                canvas.Resources.Add("unique_id", sb);
    
                // Begin the animation.
                sb.Begin();

    Here is my XAML code ..

    <Canvas x:Name="canvas" Width="1920" Height="1080">
            <Rectangle x:Name="rect1" Height="259" Width="418" Opacity="1">
                <Rectangle.Fill>
                    <SolidColorBrush Color="Gray" Opacity="0"/>
                </Rectangle.Fill>
                <Rectangle.Stroke>
                    <SolidColorBrush Color="White" Opacity="1"/>
                </Rectangle.Stroke>
            </Rectangle>
        </Canvas>


    Thanks for your thoughts

    Here is the answer:

                rect1.RenderTransform = new TranslateTransform();
                DoubleAnimation anima1 = new DoubleAnimation();
                anima1.Duration = TimeSpan.FromMilliseconds(2000);
                anima1.To = 150;
    
                Storyboard.SetTarget(anima1, rect1);
                Storyboard.SetTargetProperty(anima1, "(UIElement.RenderTransform).(TranslateTransform.X)");
                Storyboard storyboard = new Storyboard();
                storyboard.Children.Add(anima1);
                storyboard.Begin();
    

    • Edited by duffybr Monday, December 01, 2014 9:14 PM
    Monday, December 01, 2014 8:06 PM

Answers

  • Hi duffybr,

    The easiest way to figure out animations is to load the project into Blend and use its animations pane. This will generate the following to animate a render transform and canvas coordinates (the render transform is preferred since it is an independent animation):

       <Page.Resources>
    <Storyboard x:Name="SlideRectangle" AutoReverse="True"> <DoubleAnimation Duration="0:0:1" To="500" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="rect1" d:IsOptimized="True"/> <DoubleAnimation Duration="0:0:1" To="500" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="rect1" d:IsOptimized="True"/> </Storyboard> <Storyboard x:Name="CanvasSlideRect" AutoReverse="True"> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(Canvas.Left)" Storyboard.TargetName="rect1"> <EasingDoubleKeyFrame KeyTime="0" Value="0"/> <EasingDoubleKeyFrame KeyTime="0:0:1" Value="500"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(Canvas.Top)" Storyboard.TargetName="rect1"> <EasingDoubleKeyFrame KeyTime="0" Value="0"/> <EasingDoubleKeyFrame KeyTime="0:0:1" Value="500"/> </DoubleAnimationUsingKeyFrames> </Storyboard>
       </Page.Resources>

    I'd usually leave the storyboards in Xaml rather than creating it from code behind, but it's straightforward to convert these to code if you'd like. Based on your original snippet you'll get something like:

           private void Button_Click(object sender, RoutedEventArgs e)
            {
                DoubleAnimation anim1 = new DoubleAnimation();
                DoubleAnimation anim2 = new DoubleAnimation();
    
                TimeSpan duration = TimeSpan.FromSeconds(1.0);
    
                anim1.Duration = duration;
                anim2.Duration = duration;
    
                Storyboard sb = new Storyboard();
    
                sb.Duration = duration;
    
                sb.Children.Add(anim1);
                sb.Children.Add(anim2);
    
                Storyboard.SetTarget(anim1, rect1);
                Storyboard.SetTarget(anim2, rect1);
    
                //TranslateTransform trans = new TranslateTransform();
                //rect1.RenderTransform = trans;
    
                Storyboard.SetTargetProperty(anim1, "(UIElement.RenderTransform).(CompositeTransform.TranslateX)");
                Storyboard.SetTargetProperty(anim2, "(UIElement.RenderTransform).(CompositeTransform.TranslateY)");
    
                anim1.To = 500;
                anim2.To = 500;
    
    
                // Make the Storyboard a resource.
              //  canvas.Resources.Add("unique_id", sb);
    
                // Begin the animation.
                sb.Begin();
            }

    I left this as a CompositeTransform defined in the Xaml rather than swapping out a TranslateTransform as your original code did, but you could do either. You probably don't want to overwrite the Rectangle's transform in code if it's already been set, but if you can guarantee this will only run once it's not a big deal (the canvas.Resources.Add also can only be run once).

    --Rob

    • Marked as answer by duffybr Tuesday, December 02, 2014 1:07 AM
    Tuesday, December 02, 2014 12:06 AM
    Owner

All replies

  • Hi duffybr,

    The easiest way to figure out animations is to load the project into Blend and use its animations pane. This will generate the following to animate a render transform and canvas coordinates (the render transform is preferred since it is an independent animation):

       <Page.Resources>
    <Storyboard x:Name="SlideRectangle" AutoReverse="True"> <DoubleAnimation Duration="0:0:1" To="500" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="rect1" d:IsOptimized="True"/> <DoubleAnimation Duration="0:0:1" To="500" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="rect1" d:IsOptimized="True"/> </Storyboard> <Storyboard x:Name="CanvasSlideRect" AutoReverse="True"> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(Canvas.Left)" Storyboard.TargetName="rect1"> <EasingDoubleKeyFrame KeyTime="0" Value="0"/> <EasingDoubleKeyFrame KeyTime="0:0:1" Value="500"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(Canvas.Top)" Storyboard.TargetName="rect1"> <EasingDoubleKeyFrame KeyTime="0" Value="0"/> <EasingDoubleKeyFrame KeyTime="0:0:1" Value="500"/> </DoubleAnimationUsingKeyFrames> </Storyboard>
       </Page.Resources>

    I'd usually leave the storyboards in Xaml rather than creating it from code behind, but it's straightforward to convert these to code if you'd like. Based on your original snippet you'll get something like:

           private void Button_Click(object sender, RoutedEventArgs e)
            {
                DoubleAnimation anim1 = new DoubleAnimation();
                DoubleAnimation anim2 = new DoubleAnimation();
    
                TimeSpan duration = TimeSpan.FromSeconds(1.0);
    
                anim1.Duration = duration;
                anim2.Duration = duration;
    
                Storyboard sb = new Storyboard();
    
                sb.Duration = duration;
    
                sb.Children.Add(anim1);
                sb.Children.Add(anim2);
    
                Storyboard.SetTarget(anim1, rect1);
                Storyboard.SetTarget(anim2, rect1);
    
                //TranslateTransform trans = new TranslateTransform();
                //rect1.RenderTransform = trans;
    
                Storyboard.SetTargetProperty(anim1, "(UIElement.RenderTransform).(CompositeTransform.TranslateX)");
                Storyboard.SetTargetProperty(anim2, "(UIElement.RenderTransform).(CompositeTransform.TranslateY)");
    
                anim1.To = 500;
                anim2.To = 500;
    
    
                // Make the Storyboard a resource.
              //  canvas.Resources.Add("unique_id", sb);
    
                // Begin the animation.
                sb.Begin();
            }

    I left this as a CompositeTransform defined in the Xaml rather than swapping out a TranslateTransform as your original code did, but you could do either. You probably don't want to overwrite the Rectangle's transform in code if it's already been set, but if you can guarantee this will only run once it's not a big deal (the canvas.Resources.Add also can only be run once).

    --Rob

    • Marked as answer by duffybr Tuesday, December 02, 2014 1:07 AM
    Tuesday, December 02, 2014 12:06 AM
    Owner
  • Hey Thanks Rob,

    I guess I need to start playing with Blend. I definitely want to make sure I'm writing optimal code. Thanks for the insights. 

    • Marked as answer by duffybr Tuesday, December 02, 2014 1:07 AM
    • Unmarked as answer by duffybr Tuesday, December 02, 2014 1:07 AM
    Tuesday, December 02, 2014 1:06 AM