views:

21

answers:

1

I have a situation where I have a 3d Model that has a constant rotation animation. When a user touches the screen, I would like the rotation to stop, and the user's control to take over the animation of the rotation.

I tried to do this by pausing the animation, setting the angle property of the rotation locally, then resuming the rotation. However, I discovered due to dependency property precedence, my setting values is ignored while the animation is paused.

The only workaround I could come up with was to have the touch control the camera, while the animation controls the actual model. Unfortunately this causes other complexities down the line and I'd much rather that both actions control the model itself.

   //In carousel.cs 
   public void RotateModel(double start, double end, int duration)
    {
        RotateTransform3D rt3D = _GroupRotateTransformY;
        Rotation3D r3d = rt3D.Rotation;
        DoubleAnimation anim = new DoubleAnimation();
        anim.From = start;
        anim.To = end;
        anim.BeginTime = null;
        anim.AccelerationRatio = 0.1;
        anim.DecelerationRatio = 0.6;
        anim.Duration = new TimeSpan(0, 0, 0, 0, duration);
        ac = anim.CreateClock();
        ac.Completed += new EventHandler(OnRotateEnded);
        ac.Controller.Begin();
        r3d.ApplyAnimationClock(AxisAngleRotation3D.AngleProperty, ac);

}

    //In another file
    void Carousel_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
    {
        var delta = e.DeltaManipulation;         

        RotateTransform3D rt = Carousel.RotateTransform;

        ((AxisAngleRotation3D)rt.Rotation).Angle += (-e.DeltaManipulation.Translation.X/3000) * 360.0;


        e.Handled = true;


    }

    void Carousel_PreviewTouchUp(object sender, TouchEventArgs e)
    {
        Carousel.ResumeRotationAnimation();
    }

    void Carousel_PreviewTouchDown(object sender, TouchEventArgs e)
    {
        Carousel.PauseRotationAnimation();
    }
A: 

I have come across the same need (also 3D, also Model3DGroup rotation) and did it this way:

When the animation needs to stop I get the current double value of the animated property (and store it locally).

var temp = myAxisAngleRotation.Angle;

I then remove the animation from the dependency property using

myAxisAngleRotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, null);

and set the animated dependency property to the stored value.

myAxisAngleRotation.Angle = temp;

When the animation needs to resume I create a new animation that starts with the current value.

DoubleAnimation anim = new DoubleAnimation();
anim.From = myAxisAngleRotation.Angle;
anim.To = end;
anim.Duration = new TimeSpan(0, 0, 0, 0, duration);
myAxisAngleRotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, anim);

Done!

If you want your animation at a constant speed you will have to take the distance (Math.Abs(anim.To-anim.From)) into account when calculating the duration.

Once I had this. I realized this can be generalized for all linear animations and generalized it into a Behavior/AttachedProperty.

bitbonk