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:
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:
Application.DoEvent
(nor anything equivalent that would cause message pumping to occur), or is it only possible by pumping messages. If you have synchronous work that you want to do on a background thread, call it in a Task.Run
and then await
the result (the calling code treats it as asynchronous).
private Task DoWorkAsync1()
{
return Task.Delay(2000);
}
private Task DoWorkAsync2()
{
return Task.Run(() => Thread.Sleep(2000));
}
Alternatively, if your synchronous work really is immediate, and you really want to apply some UI updates (eg, cursor) before your other UI work, then you can just simply do this:
await Task.Delay(10);
Instead of DoEvents
throw in:
await Task.Run(() => { });
This will ensure that the awaited task isn't finished right when it's started, so that the remainder of the method will be run as a continuation, rather than synchronously.
Alternatively you could just add a continuation directly to doWorkAsync
that you ensure isn't run synchronously:
await doWorkAsync
.ContinueWith(t => { }, TaskContinuationOptions.HideScheduler);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.