0
public partial class Form1 : Form
{
  public Form1()
  {
    InitializeComponent();
  }

  private void button1_Click(object sender, EventArgs e)
  {
    button1.BackColor = Color.Lime;
    Thread.Sleep(5000);
    button1.BackColor = Color.DarkGreen;
  }
}

button1 is already DarkGreen. when I click button1, nothing changes.

How can I observe this change for 5 seconds?

  • 1
    wpf or winfrom? – Denis Schaf Mar 14 '19 at 14:21
  • 1
    Try inserting a button1.Refresh(); before the sleep. – TaW Mar 14 '19 at 14:21
  • This might be better achieved in Javascript, if you're using winforms or MVC. Can you be more specific about your problem? – el toro Mar 14 '19 at 14:22
  • javascript? this is c# – GottZ Mar 14 '19 at 14:22
  • @GottZ If he's making a webpage (hence why I asked "winforms or MVC"), then changing the color of a button is better done with Javascript than C# codebehind. – el toro Mar 14 '19 at 14:23
  • 3
    also your current code will freeze the Interface which is not what i can imagine you want – Denis Schaf Mar 14 '19 at 14:23
  • I recomend you NOT doing that. Read about [asyncronous programming and responsive interfaces](https://learn.microsoft.com/en-us/windows/uwp/debug-test-perf/keep-the-ui-thread-responsive). – Cleptus Mar 14 '19 at 14:25
  • Possible duplicate of [Keep UI thread responsive when running long task in windows forms](https://stackoverflow.com/questions/47913838/keep-ui-thread-responsive-when-running-long-task-in-windows-forms) – Cleptus Mar 14 '19 at 14:31
  • this is winform. and yes I know this freezes interface. the main thing I wanted to learn was that the color changes were not made before the code block ended. and how can I do this. thank you for everyone – Burak Koçyiğit Mar 14 '19 at 14:57
  • 1
    If you want to change the Button color after a number of seconds, make the `Button.Click()` handler async (`private async void button1_Click(object sender, EventArgs e)`), set the first color, then `await Task.Delay(5000)`, then set the second color. If required, disable the Button as the first thing and enable it again before the metod returns. – Jimi Mar 14 '19 at 15:41

3 Answers3

2

The reason this isn't working is because the Thread.Sleep() is blocking the thread from completing.

The window is only redrawn when the application is not doing anything, i.e. after your method completes. If you remove the line where you change it to DarkGreen you will see it change colour after five seconds.

You should use a timer to solve your problem.

If you want, you can force it to refresh the interface early without leaving the method with a call to Application.DoEvents(); which will reflect changes you've made like colour changes.

    button1.BackColor = Color.Lime;
    Application.DoEvents()
    Thread.Sleep(5000);
    button1.BackColor = Color.DarkGreen;

Note that putting a Thread Sleep is a bad idea in a program with a user interface, but for illustration purposes it will show you how to make it change colour.

NibblyPig
  • 51,118
  • 72
  • 200
  • 356
  • Not the best suggestion. OP's design could be considered wrong. You could improve this answer adding some link to a better UI design tips. – Cleptus Mar 14 '19 at 14:27
  • I could but it's outside the scope of the question, it looks like OP has tried to change a button colour for five seconds just to see how, and has accidentally stumbled upon a quirk of forms applications in that they only update when the thread is not busy doing something else. I've explained how forms applications work, and why the colour changing test wasn't working, and that Thread Sleep is a bad idea in a forms application. I think that should be sufficient. – NibblyPig Mar 14 '19 at 14:32
  • as far as I understand the problem before the block of code runs out of the event. and we can overcome this problem by calling Application.DoEvents () in the code block. thank you for help – Burak Koçyiğit Mar 14 '19 at 15:03
  • You just need to call `button1.Update();` to update the button immediately, no need to call `Application.DoEvents()`. You may also want to consider async/await way which I described in the other answer's [comments](https://stackoverflow.com/questions/55164889/how-to-change-backcolor-of-button-at-run-time#comment97077312_55166332) which does the trick without blocking UI thread. – Reza Aghaei Mar 14 '19 at 17:53
  • Academic though since it's basically the same thing, Update() just forces an interop message to redraw the window, application doevents tells windows to do everything that's queued to be done which will include the same message. Yes you should use async await to do it properly but I don't think the OP is trying to get a button to show for 5 seconds, they're trying to figure out how to change the colour of a button. The async example below is not good either because you shouldn't access controls directly from a separate thread. – NibblyPig Mar 15 '19 at 09:02
2

Your issue is because the UI thread is being blocked. You need to run this logic in a separate thread. Try this code instead:

private async void button1_Click(object sender, EventArgs e)
{
    button1.BackColor = Color.LimeGreen;
    await Task.Run(() =>
    {
        System.Threading.Thread.Sleep(5000);
        button1.BackColor = Color.DarkGreen;
    });
}

This will turn your button to a LimeGreen, then wait 5 seconds and turn it back to DarkGreen. This works because we are spinning it up in a new thread and therefore, doesn't lock the UI.

Icemanind
  • 47,519
  • 50
  • 171
  • 296
  • No need to `Task.Run` in an async method in this case. You also are accessing the UI element from another thread when you set the `BackColor` of the button in `Task.Run`. Simply doing this in an async method would be enough: `button1.BackColor = Color.LimeGreen;await Task.Delay(5000);button1.BackColor = Color.DarkGreen;` – Reza Aghaei Mar 14 '19 at 17:45
  • This doesn't look thread safe, it might work in this instance but it's not a good practice, you should use `BeginInvoke()` if you're going to access a form's controls from a separate thread. – NibblyPig Mar 15 '19 at 09:03
0

I wouldn't recommend using Thread.Sleep() because it will freeze your Interface. Also you need to refresh the button so the changes shown. You can use async and wait methods for delaying your button color change Add async after the private keyword on the button1_click function and create the async Task function and remove the Thread.Sleep() function with await awaiting();

public partial class Form1 : Form
{
    public Form1()
{
    InitializeComponent();
}

private async void button1_Click(object sender, EventArgs e)
{
    button1.BackColor = Color.Lime;
    button1.Refresh();
    await awaiting();

    button1.BackColor = Color.DarkGreen;
}
private async Task awaiting() {
        await Task.Delay(5000);
    }
}
callme_wiz
  • 43
  • 2
  • 8
  • No need to call `button1.Refresh();` because UI thread is not blocked and will do the repaint after setting back color to lime. – Reza Aghaei Mar 14 '19 at 17:55