Home > Software engineering >  Cannot get Thread and animation Rotation to work
Cannot get Thread and animation Rotation to work

Time:11-17

This is my control:

enter image description here

I am getting this to rotate, with this code:

Global variable, bool IsTriangleAnimRunning = false; And the rest of the code:

public void AnimateTriangle()
        {
            var rotation = (int)((100 / 100d) * 45 * 1); // Max 45 degree rotation
            var duration = (int)(750 * (100 / 100d)); // Max 750ms rotation

            while (IsTriangleAnimRunning != false)
            {
                MyTriangle.Dispatcher.BeginInvoke(
               (Action)(() =>
               {
                   var anim = new DoubleAnimation
                   {
                       To = rotation,
                       Duration = new Duration(TimeSpan.FromMilliseconds(duration)),
                       AutoReverse = true
                   };

                   var rt = new RotateTransform();
                   MyTriangle.RenderTransform = rt;
                   rt.BeginAnimation(RotateTransform.AngleProperty, anim);

               }), DispatcherPriority.ContextIdle);

                Thread.Sleep(duration * 2);
            }
        }

The event handler for the button, that triggers the animation:

 public void HandleTriangleEvents(object sender, RoutedEventArgs a) 
        {
            Thread t_triagle = new Thread(new ThreadStart(this.AnimateTriangle));

            Button btn = (Button)sender;
            if (btn.Name == "btnStartTriangleAnim")
            {
                IsTriangleAnimRunning = true;
                btnStartTriangleAnim.IsEnabled = false;
                t_triagle.Start();
            }
            else
            {
                IsTriangleAnimRunning = false;
                btnStartTriangleAnim.IsEnabled = true;
                t_triagle.Abort();
            }
        }

It behaves in an unatural way, because, when I stop it, it resets to its regular position. I am assuming it, does this for some reason, that I cannot understand. Also, for some reason, this code does not get it to run constantly, but only once.

Desired functionality: If, I hit start button, run the thread and keep on rotating, while thread is running. If, I hit, stop, then stop in the current state of rotation. If I hit start, run the thread again and keep rotating back and forth.

--

Tested with Task Async, runs slower and doesn't repeat.

  private async Task AnimateTriangle()
        {
            double rotation = 45d;
            double duration = 100d;

            var anim = new DoubleAnimation
            {
                To = rotation,
                Duration = TimeSpan.FromMilliseconds(duration),
                AutoReverse = true,
                RepeatBehavior = RepeatBehavior.Forever
            };

            var transform = MyTriangle.RenderTransform as RotateTransform;

            await Task.Factory.StartNew(() =>
            {
                while (IsTriangleAnimRunning != false)
                {
                    MyTriangle.Dispatcher.Invoke(() =>
                    {
                        if (transform == null)
                        {
                            transform = new RotateTransform();
                            MyTriangle.RenderTransform = transform;
                        }

                        transform.BeginAnimation(RotateTransform.AngleProperty, anim);

                    }, DispatcherPriority.ContextIdle);        

                    if (IsTriangleAnimRunning == false)
                    {
                        MyTriangle.Dispatcher.Invoke(() =>
                        {
                            if (MyTriangle.RenderTransform is RotateTransform)
                            {
                                var angle = transform.Angle; // current animated value
                                transform.Angle = angle;
                                transform.BeginAnimation(RotateTransform.AngleProperty, null);
                            }
                        }, DispatcherPriority.ContextIdle);
                    }
                }
            });
        }

CodePudding user response:

You do not need to start a thread.

Start an animation that runs forever, until you reset it by setting a null animation.

Before you reset it, explicitly set the value of the target property to the current animated value.

Reuse the existing RotateTransform instead of re-assigning one each time you start the animation.

private void StartButtonClick(object sender, RoutedEventArgs e)
{
    double rotation = 45d;
    double duration = 750d;

    var anim = new DoubleAnimation
    {
        To = rotation,
        Duration = TimeSpan.FromMilliseconds(duration),
        AutoReverse = true,
        RepeatBehavior = RepeatBehavior.Forever
    };

    var transform = MyTriangle.RenderTransform as RotateTransform;

    if (transform == null)
    {
        transform = new RotateTransform();
        MyTriangle.RenderTransform = transform;
    }

    transform.Angle = 0d;
    transform.BeginAnimation(RotateTransform.AngleProperty, anim);
}

private void StopButtonClick(object sender, RoutedEventArgs e)
{
    if (MyTriangle.RenderTransform is RotateTransform transform)
    {
        var angle = transform.Angle; // current animated value
        transform.Angle = angle;
        transform.BeginAnimation(RotateTransform.AngleProperty, null);
    }
}
  • Related