Kristof
Topic Author
Posts: 19
Joined: 22 Apr 2014, 14:44

Cannot create an animation in code-behind

30 Jun 2014, 15:39

It's great that you can set up animations in your XAML file. However I have a situation where I want to set up an animation in the code-behind.

In my code I have a scrollviewer because not all content fits on the screen. If an item is made 'active' (from code behind), I want this scrollviewer to smoothly scroll towards this item. It is important that this is a smooth animation. I tried to do this using this code:
DoubleAnimation anim = new DoubleAnimation();
anim.SetFrom(new Noesis.NullableFloat(scrollViewer.GetHorizontalOffset()));
anim.SetTo(new Noesis.NullableFloat(_scrollViewerGoal));
anim.SetDuration(new Duration(new Noesis.TimeSpan(0.5)));
scrollViewer.BeginAnimation(ScrollViewer.HorizontalOffsetProperty, anim);
Unfortunately the 'BeginAnimation' method from WPF is not present in NoesisGUI.

Is there some workaround so I can set up an animation from code-behind?
 
User avatar
sfernandez
Site Admin
Posts: 3222
Joined: 22 Dec 2011, 19:20

Re: Cannot create an animation in code-behind

03 Jul 2014, 20:55

You are right, BeginAnimation is not yet supported. We add it to our feature list for a future update.

Meanwhile you can create a Storyboard and play it:
DoubleAnimation anim = new DoubleAnimation();
anim.SetFrom(new Noesis.NullableFloat(scrollViewer.GetHorizontalOffset()));
anim.SetTo(new Noesis.NullableFloat(_scrollViewerGoal));
anim.SetDuration(new Duration(new Noesis.TimeSpan(0.5)));

Storyboard.SetTarget(anim, scrollViewer);
Storyboard.SetTargetProperty(anim, new PropertyPath(ScrollViewer.HorizontalOffsetProperty));

Storyboard storyboard = new Storyboard();
storyboard.GetChildren().Add(anim);

storyboard.Begin(scrollViewer);
 
Daki
Posts: 57
Joined: 16 Aug 2013, 00:48

Re: Cannot create an animation in code-behind

13 Aug 2014, 03:29

Somewhat related, I am having trouble animating the transform of an object programmatically, not in a code behind but just in my game. I am using the native library. I have Canvas which I can move by setting its RenderTransform to a new TranslateTransform but I can't seem to figure out how to animate the translation. Do you know how I might accomplish this?
 
User avatar
sfernandez
Site Admin
Posts: 3222
Joined: 22 Dec 2011, 19:20

Re: Cannot create an animation in code-behind

13 Aug 2014, 17:19

Somewhat related, I am having trouble animating the transform of an object programmatically, not in a code behind but just in my game. I am using the native library. I have Canvas which I can move by setting its RenderTransform to a new TranslateTransform but I can't seem to figure out how to animate the translation. Do you know how I might accomplish this?
You can create a complete Storyboard from code (as explained before) or you can design the animation in Blend, assign names to the required KeyFrames or Animations, modify the desired values and Begin the animation from code.

If you want to animate the translation of an element, that element should define the proper Transform element first:
<Canvas x:Name="MyCanvas" RenderTransformOrigin="0.5,0.5">
    <Canvas.RenderTransform>
        <TranslateTransform />
    </Canvas.RenderTransform>
</Canvas>
Then the animation should point to that element and the property path point to the TranslateTransform property you want to modify:
<Storyboard x:Key="MoveCanvas">
    <DoubleAnimation
        Storyboard.TargetElement="MyCanvas"
        Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"
        Durantion="0:0:1" To="200"/>
</Storyboard>
Equivalent code:
DoubleAnimation anim = new DoubleAnimation();
anim.SetTo(new Noesis.NullableFloat(200.0f));
anim.SetDuration(new Duration(new Noesis.TimeSpan(1)));

Storyboard.SetTarget(anim, myCanvas);
Storyboard.SetTargetProperty(anim, new PropertyPath(
    "(UIElement.RenderTransform).(TranslateTransform.X)"));

Storyboard storyboard = new Storyboard();
storyboard.GetChildren().Add(anim);

storyboard.Begin(myCanvas);
 
Daki
Posts: 57
Joined: 16 Aug 2013, 00:48

Re: Cannot create an animation in code-behind

14 Aug 2014, 03:38

Thanks for your response. I have the animation set up but when I play it I do not see the canvas move and I am unsure why.

The canvas in xaml is defined as:
<Canvas x:Name="difficultyring" RenderTransformOrigin="0.5,0.5" Height="307.824" Canvas.Left="-15.307" Canvas.Top="15.111" Width="203.852" d:IsHidden="True">
				<Canvas.RenderTransform>
					<TranslateTransform />
				</Canvas.RenderTransform>
                <Rectangle Fill="{StaticResource difficultyring}" Stretch="Fill" Height="203.852" Width="203.852" />
              </Canvas>
In code I have:
Noesis::Gui::Nullable<NsFloat32> endPoint = m_difficulty * m_distanceBetweenRatingBackgrounds;
		NsFloat64 time = 0.5;
		Noesis::Gui::TimeSpan timeSpan(time);
		Noesis::Gui::Duration duration(timeSpan);
		Noesis::Gui::DoubleAnimation* pAnim = new Noesis::Gui::DoubleAnimation();
		pAnim->SetTo(endPoint);
		pAnim->SetDuration(duration);

		Storyboard::SetTarget(pAnim, m_pDifficultyRing);
		Storyboard::SetTargetProperty(pAnim, new Noesis::Gui::PropertyPath(Noesis::Gui::TranslateTransform::XProperty));

		Noesis::Gui::Storyboard* pStoryboard = new Noesis::Gui::Storyboard();
		pStoryboard->GetChildren()->Add(pAnim);
		pStoryboard->Begin(m_pDifficultyRing);
I added a delegate for the storyboard completion and that gets called at the appropriate time so the animation is updating/completing.

Also if I just set the transform of the canvas directly to my end point it shows up in the correct spot.
 
User avatar
sfernandez
Site Admin
Posts: 3222
Joined: 22 Dec 2011, 19:20

Re: Cannot create an animation in code-behind

14 Aug 2014, 04:30

There is something wrong in your code.

The PropertyPath is pointing to the TranslateTransform::XProperty, but the Target (the Canvas) does not contain this property. You have to use a chained property path as I specified in my previous post (this is what Blend generates when you animate that property):
...
Storyboard::SetTarget(pAnim, m_pDifficultyRing);
Ptr<PropertyPath> path = *new Noesis::Gui::PropertyPath(
    "(UIElement.RenderTransform).(TranslateTransform.X)");
Storyboard::SetTargetProperty(pAnim, path.GetPtr());
...
Or you can simplify the path if property owner is not specified (both codes are equivalent):
...
Storyboard::SetTarget(pAnim, m_pDifficultyRing);
Ptr<PropertyPath> path = *new Noesis::Gui::PropertyPath("RenderTransform.X");
Storyboard::SetTargetProperty(pAnim, path.GetPtr());
...
You have to reach the RenderTransform of the Canvas first, then the X property of the TranslateTransform.

It should work if you change your code like this.

P.S. Pay attention to the creation of objects, because they are created with 1 reference. If you don't use Ptr, you should Release() your reference after transferring the ownership of the object to another entity. Otherwise you will be leaking memory. But I recommend you to use Ptr with the *new constructor (as I did in the previous code with the PropertyPath) to track object references automatically.
 
timashev
Posts: 28
Joined: 22 Jan 2014, 00:47

Re: Cannot create an animation in code-behind

22 Dec 2014, 13:28

I've tried to animate ScrollViewer.HorizontalOffsetProperty using Storyboard, and it just don't work :(

I've copied the example by sfernandez posted on 03 Jul 2014, 22:55 here, and it seems it's not working (with 1.1.14 at least). Please either confirm that it's not supported, or provide a working example :)
 
User avatar
sfernandez
Site Admin
Posts: 3222
Joined: 22 Dec 2011, 19:20

Re: Cannot create an animation in code-behind

29 Dec 2014, 13:36

I've tried to animate ScrollViewer.HorizontalOffsetProperty using Storyboard, and it just don't work :(

I've copied the example by sfernandez posted on 03 Jul 2014, 22:55 here, and it seems it's not working (with 1.1.14 at least). Please either confirm that it's not supported, or provide a working example :)
Hi, sorry for the very late answer on these holidays.

Both ScrollViewer's HorizontalOffset and VerticalOffset properties are read-only, so you cannot animate them directly. What you can do is use an attached property to indirectly animate them by calling ScrollToHorizontalOffset() or ScrollToVerticalOffset():
namespace Animation
{
    [Extended]
    public class Extensions : BaseComponent
    {
        public static DependencyProperty VerticalScrollProperty = DependencyProperty.Register(
            "VerticalScroll", typeof(float), typeof(Extensions),
            new PropertyMetadata(0.0f, Extensions.OnVerticalOffsetChanged));

        public static float GetVerticalOffset(DependencyObject d)
        {
            return d.GetValue<float>(VerticalScrollProperty);
        }

        public static void SetVerticalOffset(DependencyObject d, float offset)
        {
            d.SetValue<float>(VerticalScrollProperty, offset);
        }

        static void OnVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ScrollViewer scroll = d.As<ScrollViewer>();
            if (scroll != null)
            {
                float offset = scroll.GetValue<float>(VerticalScrollProperty);
                scroll.ScrollToVerticalOffset(offset);
            }
        }
    }
}
<Grid
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="clr-namespace:Animation">
    <Grid.Resources>
        <Storyboard x:Key="anim" AutoReverse="True" RepeatBehavior="Forever">
            <DoubleAnimation Storyboard.TargetName="scroll" Storyboard.TargetProperty="(local:Extensions.VerticalScroll)"
                Duration="0:0:2" From="0" To="100"/>
        </Storyboard>
    </Grid.Resources>
    <Grid.Triggers>
        <EventTrigger RoutedEvent="FrameworkElement.Loaded">
            <EventTrigger.Actions>
                <BeginStoryboard Storyboard="{StaticResource anim}"/>
            </EventTrigger.Actions>
        </EventTrigger>
    </Grid.Triggers>
    <Border BorderBrush="Silver" BorderThickness="1" HorizontalAlignment="Center" VerticalAlignment="Center">
        <ScrollViewer x:Name="scroll" Width="200" Height="200"
            ScrollViewer.HorizontalScrollBarVisibility="Visible"
            ScrollViewer.VerticalScrollBarVisibility="Visible">
            <Ellipse Fill="Blue" Width="300" Height="400"/>
        </ScrollViewer>
    </Border>
</Grid>

Who is online

Users browsing this forum: Google [Bot] and 3 guests