nan
nan

Reputation: 1191

How to smooth WPF animation?

I am struggling in smoothing WPF animation

Actually my animation code is as follows:

private void AnimateX ( FrameworkElement element, double XMoveStart, double XMoveEnd, int secondX)
{

    SineEase eEase = new SineEase();
    eEase.EasingMode = EasingMode.EaseInOut;
    Storyboard sb = new Storyboard();

    DoubleAnimation daX = new DoubleAnimation(XMoveStart, XMoveEnd, new Duration(new TimeSpan(0, 0, 0, secondX, 0)));
    daX.EasingFunction = eEase;
    Storyboard.SetTargetProperty(daX, new PropertyPath("(Canvas.Left)"));

    sb.Children.Add(daX);

    element.BeginStoryboard(sb);
}

The above code is a method to move an object horizontally with sine ease. When only one object is moving, it is OK. However, whenever two or more objects move together (call AnimateX method on another object when the previous animation has not yet completed), the animation starts to become jittery. By jittery I mean, the objects are kind of shaking during the course of animation.

Upvotes: 1

Views: 4117

Answers (2)

Jean-Francois Gariepy
Jean-Francois Gariepy

Reputation: 21

I faced the same problem many times. I found out that depending on the objects you add to your canvas, WPF will often have to regenerate representations of these objects on every frame (which I believe might be your case, depending on the type of UI elements you are manipulating). You can solve the jitter issue by telling WPF to cache a representation of your canvas in a bitmap. This is done very simply as follows, in your Xaml definition of the canvas:

<Canvas ...Your canvas properties...>
    <Canvas.CacheMode>
        <BitmapCache />
    </Canvas.CacheMode>
    ...Your objects...
</Canvas>`

This reduces the load on your WPF application, as it simply stores the representation of your objects as a bitmap image, and as a consequence your application does not have to redraw them on every frame. This solution only works if your animation is applied externally to the canvas, and that there is no on-going local animations applying to the individual objects drawn in your canvas. You'll want to create separates canvases with their own caching if other animations in your code move the two objects with respect to each other.

Note that some UI elements will not be eased by this strategy. However, I've seen this strategy work efficiently for many elements, including TextBoxes and the likes, as well as geometric shapes. In any case, it's always worth the try.

Secondly, if caching local representations does not suffice, then you might want to have a look at the performance of your code and see if any process could be responsible for blocking the UI momentarily. There is no uniform solution regarding this aspect and it depends on what else is putting strain on your application UI. Cleaning the code and using asynchronous processes where relevant could help.

Finally, if, after all these checks the overall demand on your application remains too high, you can somewhat remove some strain on the application by reducing its general frame rate, the default being 60. You can try 30 or 40 and see if this improves the jittering by including the following code in your initialization:

Timeline.DesiredFrameRateProperty.OverrideMetadata(typeof(Timeline), new FrameworkPropertyMetadata { DefaultValue = 40 });

Upvotes: 1

Clemens
Clemens

Reputation: 128061

Just a guess, but what happens if you directly animate the property, withoud using a Storyboard?

private void AnimateX(FrameworkElement element, double xMoveStart, double xMoveEnd, double durationSeconds)
{
    DoubleAnimation animation = new DoubleAnimation
    {
        From = xMoveStart,
        To = xMoveEnd,
        Duration = TimeSpan.FromSeconds(durationSeconds),
        EasingFunction = new SineEase { EasingMode = EasingMode.EaseInOut }
    };

    element.BeginAnimation(Canvas.LeftProperty, animation);
}

Upvotes: 0

Related Questions