所有工作同步时显示等待光标

时间:2013-08-20 18:12:28

标签: c# winforms async-await

在我的Winforms应用程序中,当您启动操作时,它可能会也可能不会异步完成。如果工作全部同步完成,我无法使用我异步完成工作时使用的相同方法显示等待光标。

以下是显示问题的示例:

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); 
    }
}

在这个例子中:

  • 单击button1会显示等待光标(因为工作是异步完成的)。
  • 点击button2 显示等待光标(因为所有工作都是同步完成的)。
  • 单击button1和button2会导致UI按预期被禁用。

所需要的是单击button1或button2会导致在单击按钮和UI更新工作完成之间的整个时间间隔内显示等待光标。

问题:

  • 有没有办法在不插入Application.DoEvent的情况下解决这个问题(也没有任何可能导致消息发生的等效事项),或者只能通过抽取消息来解决这个问题。
  • 暂且不说:为什么禁用控件正常工作(与光标不同)。

2 个答案:

答案 0 :(得分:0)

如果您要在后台线程上进行同步工作,请在Task.Run中调用它,然后await调用结果(调用代码将其视为异步)。

private Task DoWorkAsync1()
{
    return Task.Delay(2000); 
}

private Task DoWorkAsync2()
{
    return Task.Run(() => Thread.Sleep(2000));
}

或者,如果您的同步工作确实是即时的,并且您真的想在其他UI工作之前应用一些UI更新(例如光标),那么您可以简单地执行此操作:

await Task.Delay(10);

答案 1 :(得分:0)

而不是DoEvents投入:

await Task.Run(() => { });

这将确保等待任务在启动时没有完成,因此方法的其余部分将作为延续而不是同步运行。

或者,您可以直接向doWorkAsync添加延迟,确保不会同步运行:

await doWorkAsync
    .ContinueWith(t => { }, TaskContinuationOptions.HideScheduler);