1

This is my method inside a class in my Form. I'm using a custom image background on my buttons, and I want to change them so that they appear to animate:

 private void restaurantButton_Click(object sender, EventArgs e)
    {

        System.Threading.Thread.Sleep(75);
        restaurantButton.BackgroundImage = Properties.Resources.buttonBackClicked;
        System.Threading.Thread.Sleep(150);
        restaurantButton.BackgroundImage = Properties.Resources.buttonBack;
    }

The animation happens if I give it a single change. The above code doesn't appear to do anything. Please help, and if you can, suggest another way to animate controls manually (i.e. control image, click time, etc.) in VC# (VS2013).

salmonlawyer
  • 7
  • 1
  • 3

2 Answers2

2

You're sleeping on the UI thread, preventing the UI from updating.

Instead, use await Task.Delay() for a non-blocking wait.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Could you explain with a little more detail? Even though I sleep, I do so for only 75 ms, and I wait for that to complete, because this is a basic forms application with only two forms... – salmonlawyer Apr 20 '15 at 19:07
  • @salmonlawyer: The UI needs time to update after you make changes, but while you're sleeping on the UI thread, all UI updates are frozen or paused. So essentially, you are not giving the UI any time to update or change states. If you use the method that SLaks suggested instead of Thread.Sleep, this happens asynchronously, which means it doesnt sleep on the UI thread and uses callbacks. You should look into how threading work and how asynchronous operations execute on a separate thread and use callbacks etc. – caesay Apr 20 '15 at 19:45
  • @caesay Thank you for the suggestion, I'm reading up, but it's currently confusing me. I need more time I guess. All help is appreciated. – salmonlawyer Apr 20 '15 at 20:54
2

The problem is that you are blocking the UI thread and not allowing it to update. You are only using one thread here, that same thread happens to be the one that is making visual updates to your UI. So, if you put the thread to sleep that is updating your UI, it will not update (because it's asleep).

To solve this, you need to asynchronously wait on a separate thread. The async/await keyword that were introduced in .Net 4.5 will make this very easy, see the code below:

private async void restaurantButton_Click(object sender, EventArgs e)
{
    await Task.Delay(75);
    restaurantButton.BackgroundImage = Properties.Resources.buttonBackClicked;
    await Task.Delay(150);
    restaurantButton.BackgroundImage = Properties.Resources.buttonBack;
}

When you call await, what is actually happening is that the current thread is being released (freed) and Task.Delay is being executed on another thread. When that second thread is finished (waiting, in this case), it signals back to your main thread to continue.

caesay
  • 16,932
  • 15
  • 95
  • 160
bkribbs
  • 734
  • 1
  • 6
  • 24
  • There is really no point to just repeating what Slaks said, instead of giving him code to just drop in and replace, they should be given the direction so they can find out why they do it and implement it. – caesay Apr 20 '15 at 20:26
  • Sorry, I admit I'm a little new to stackoverflow. Is that universal throughout the site? I find that I learn the best simply by seeing examples of code and understanding how they work. So if I was asking this question, I would simply look at SLaks answer and would then have to google some more on the async/await functionality whereas I tried to just do that part for the OP. I also thought it was worth mentioning the snippet about removing the bottom line would allow the UI to update, as the OP appeared to think his code wasn't functioning at all. – bkribbs Apr 20 '15 at 20:36
  • Perhaps it would have been more appropriate to give a different piece of example code though, where they can see how it works, rather than just modifying their code for them. – bkribbs Apr 20 '15 at 20:41
  • Isn't there only a single thread for the UI calls? I haven't used any threads here, so IIRC, the thread being put to sleep is the one and only main thread, which means that when it wakes it executes the next step... Please correct me if I'm wrong, I'm very much confused... – salmonlawyer Apr 20 '15 at 20:51
  • @salmonlawyer: That is the problem. If you put the thread that is drawing your UI updates to sleep, then it cant update your UI!!! That is why using asynchronous functions to wait on a separate thread will allow your UI to update in the mean time. – caesay Apr 20 '15 at 20:52
  • EDIT- Whoops, caesay beat me to it. Leaving this for the link with another explanation...You are correct. You are using only one thread. The best explanation I have found for why sleeping this thread will freeze the UI is here: http://stackoverflow.com/questions/27356165/why-does-thread-sleep-freeze-the-form – bkribbs Apr 20 '15 at 20:55
  • This is the correct solution to my problem, thanks so much for helping me out all of you guys... – salmonlawyer Apr 20 '15 at 21:00