Search code examples
c#multithreadingwinformslabel

C# - Animate a Winforms Control


I'm trying to develop some sort of "animation" for a control in winforms that will run in a new thread than the main one.

So the code I used for the animation is the one I leave you below (a label control that scrolls up pixel by pixel every few seconds until it reaches 0 pixels):

private void LabelAnimation(int amount)
{
    this.Invoke((MethodInvoker)delegate
    {
        int currentX = Label.Location.X;

        Label.Text = amount.ToString();

        for (int h = 1; h < 7; h++)
        {
            int subtractHeight = h;
            int currentY = Label.Location.Y;

            Label.Location = new Point(currentX, (currentY - subtractHeight));

            Thread.Sleep(200);
        }
    });
}

And the method in which the new thread is created:

private void ExecuteAnimation()
{
    Thread t = new Thread(() => LabelAnimation(100));
    t.Start();
}

The problem is that in itself it works but on a graphic level it sucks, I mean, instead of moving the entire control, the text string remained in the same position while the rectangle of the label moved in the indicated direction, covering its own string.


Solution

  • Use System.Timers.Timer.
    It`s recommended to use a timer instead of sleeping the thread.
    Here is one way to achieve this:

    private System.Timers.Timer timer;
    private int amount = 100;
    private void ExecuteAnimation()
    {
         new Thread(() =>
        {
            // Set DoubleBuffered to true for smoother animation 
            this.DoubleBuffered = true;
            if (timer == null)
            {
                timer = new System.Timers.Timer();
                timer.Interval = 100;
                timer.Elapsed += timer_tick;
            }
    
            timer.Start();
        }).Start();           
    }
    
    private void timer_tick(object sender, EventArgs e)
    {
        this.Invoke(new Action(() =>
        {
            int currentX = label1.Location.X;
            label1.Text = amount.ToString();
    
            if (label1.Location.Y > 0)
            {
                label1.Location = new Point(currentX, label1.Location.Y - 1);
            }
        }));
    }
    

    OUTPUT:

    enter image description here