In my Winforms application when you start an operation it may or may not be done asynchronously. In the case that the work is all done synchronously, I cannot get the wait cursor to show up using the same approach I use when the work is done asynchronously.
Here's an example showing the issue:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var t = ButtonClick(button1, DoWorkAsync1);
}
private void button2_Click(object sender, EventArgs e)
{
var t = ButtonClick(button2, DoWorkAsync2);
}
private async Task ButtonClick(Button btn, Func<Task> doWorkAsync)
{
// Disable the UI and show the wait cursor
btn.Text = "Working...";
btn.Enabled = false;
UseWaitCursor = true;
// Application.DoEvents(); // Inserting this causes the problem to go away.
await doWorkAsync();
// Simulate an update of the UI taking a long time
Thread.Sleep(2000);
// Renable the UI and stop showing the wait cursor
UseWaitCursor = false;
btn.Enabled = true;
}
private Task DoWorkAsync1()
{
// Work takes some time
return Task.Delay(2000);
}
private Task DoWorkAsync2()
{
// Work doesn't take any time, results are immediately available
return Task.FromResult<int>(0);
}
}
In this example:
- Clicking button1 does show the Wait cursor (because the work is done asynchronously).
- Clicking button2 does not show the Wait cursor (because the work is all done synchronously).
- Clicking either button1 and button2 does result in the UI being disabled as expected.
What is desired is that clicking either button1 or button2 should cause the Wait cursor to be displayed for the entire interval between clicking the button and the UI update work being completed.
Question:
- Is there a way to solve this without inserting an
Application.DoEvent
(nor anything equivalent that would cause message pumping to occur), or is it only possible by pumping messages. - As an aside: why does the disabling of the control work correctly (unlike the cursor).