在 Thread.Sleep() 期间保持 UI 响应

Keeping UI responsive during a Thread.Sleep()

背景:我正在编写一个遍历服务器列表并获取有关每台机器的各种详细信息的应用程序。在迭代过程中,我需要更新表单上的各种控件(以显示获取信息的摘要)。因为它遍历列表,所以我调用了 Thread.Sleep() 以允许用户在询问下一台机器之前有时间阅读信息。下面是我的代码:

Task TestTask = Task.Factory.StartNew(() =>
            {
                foreach (String IpAddress in ServersToCheck)
                {
                    if (IpAddress != String.Empty)
                    {
                        ServerBeingCheckedLabel.Text = IpAddress;
                        if (PingServer(IpAddress) == true)
                        {
                            PingChar_Label.ForeColor = Color.Green;
                            PingChar_Label.Text = "a";
                            CheckPermissionsAreValid(IpAddress);
                        }
                        else
                        {
                            PingChar_Label.ForeColor = Color.Red;
                            PingChar_Label.Text = "r";
                            PermChar_Label.ForeColor = Color.Red;
                            PermChar_Label.Text = "r";
                        }
                    }
                }
                Thread.Sleep(10000);
                this.BackColor = FormBackGroundColor;
                TestButton.Enabled = true;
                RunTimer.Enabled = true;
            }, CancellationToken.None, TaskCreationOptions.None, UiScheduler);

这在更新表单上的控件方面工作正常,但在 Thread.Sleep() 期间 UI 锁定。当然,如果 Thread.Sleep() 在单独的任务上调用,UI 线程是否保持畅通?

使用 Task.Delay 而不是 Thread.Sleep 查看 This link 了解更多详情

Task.Delay 应该符合您的需要。

改变

Task.Factory.StartNew(() =>

Task.Factory.StartNew(async () =>

并改变

Thread.Sleep

await Task.Delay

如果您将 UiScheduler 作为 TaskScheduler 传递,则该任务是 UI 线程上的 运行。所以是的,当您调用 Thread.Sleep.

时,UI 线程被完全阻塞

如果要延迟,请使用 await Task.Delay(10000) 而不是异步延迟。

这将使从 Task.Factory.StartNew 返回的任务成为 Task<Task>,因为它不像 Task.Run 那样在构建时考虑了异步等待。要解决此问题,请在返回的任务上使用 Task.Unwrap

Task<Task> TestTask = Task.Factory.StartNew(async () =>
{
    // ...
    await Task.Delay(10000);
    // ...
}, CancellationToken.None, TaskCreationOptions.None, UiScheduler);

Task actualTask = TestTask.Unwrap();