The technical reason for this, is the UI works on a Message Pump (in the case of WinForms, or similar in regards to WPF). Basically a message pump is a queue of work items to do, and a while loop like the following:
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
What is happening, is that when you are processing your click:
- The click goes into the message queue
- Gets processed by the message pump
- Goes into your click method
- Blocks the thread for x amount of seconds, its still in your method and the pump can't process.
Why?
Thread.Sleep()
Suspends the current thread for the specified amount of time.
In short, no other messages get processed. In your example you sleep the thread before the pump has had time to process your colour change yet (its still stick processing your click).
When the messages eventually process, it goes through the backlog (your color changes being part of that), then without pause quickly changes it from one to the other.
The fix is quite simple, you need to allow your pump to process messages while you wait and as the other answers have eluded to, in modern version on .net we can use the async
await
pattern, and take advantage of the Task.Delay()
method.
When the program process anything that is prefixed with await
,
- If you are on the UI thread it captures the context
- Starts another thread with a continuation,
- lets the message pump continue processing.
- When the task has finished (and your delay is over), it returns control back to the original context (the thread you called it from).
Hey presto. Everything is as it should be.