【问题标题】:How to execute wait time on a seperate thread to stop UI from freezing如何在单独的线程上执行等待时间以阻止 UI 冻结
【发布时间】:2015-05-06 09:24:39
【问题描述】:

我正在尝试增加楼层,每次楼层的状态都应该改变并显示在楼层上,慢慢增加到所需的楼层。但是地板只是等待然后直接跳到他想要的地板而我没有看到它逐渐增加。我假设这是因为 UI 每次进入睡眠状态时都会冻结,因此我看不到逐渐增加。

那么我如何在另一个线程上执行等待(如果这甚至是问题)以阻止 UI 不冻结?

这是我的代码:

        while (floor > elevator.currentFloor)
        {
            elevator.currentFloor++;
            changeStatus(elevator);
            currentFloorLbl.Text = "Current Floor: " + elevator.currentFloor;
            System.Threading.Thread.Sleep(500);
        }

【问题讨论】:

  • 您需要在不同的线程上运行整个 while 循环,可能使用 BackgroundWorker 或 Task.Factory.StartNew(...)。
  • @failedprogramming 失败。
  • 我可以举个例子吗?
  • 这是一个教程,展示了使用 BackgroundWorker 更新标签 - 应该与您尝试实现的目标相似。 codeproject.com/Articles/99143/…

标签: c# multithreading loops while-loop wait


【解决方案1】:

假设您使用的是 Win Forms,请将您的代码移动到 System.Windows.Forms.Timer。如果没有,请使用appropriate .NET timer

【讨论】:

  • 大卫,很好的解决方案;不过,我会给他举个例子。
  • 鉴于CurrentFloorLbl 可能是一个 UI 元素,这对于 OP 来说将过于复杂。坚持单线程,使用 .net 4.5
  • System.Windows.Forms.Timer 的 MSDN 文章有一个很好的例子。
  • @Aron - System.Windows.Forms.Timer 在 UI 线程上被回调,因此可以更新 UI。
  • @DavidChing 我说这太复杂了,并非不可能。我们应该在这里教授当前的方法。否则你应该建议,“新建一个线程,运行一个循环,使用 Form.BeginInvoke 将信号编组回 UI 线程,运行更新......等等等等”......
【解决方案2】:
    while (floor > elevator.currentFloor)
    {
        elevator.currentFloor++;
        changeStatus(elevator);
        currentFloorLbl.Text = "Current Floor: " + elevator.currentFloor;
        await Task.Delay(500);
    }

如您所见,我们使用的是await Task.Delay(500) 而不是Thread.Sleep(500)。它们都实现了相同的目的,即停止执行代码 500 毫秒。

不同的是Thread.Sleep(500)就是我们所说的阻塞调用。它告诉您的线程(UI 线程,在屏幕上绘制的线程)进入睡眠状态。这意味着您的 UI 在此期间无法更新。

另一方面,await 的意思是,这里有一些代码会告诉您何时完成。在完成之前,出去做点别的事情(比如更新 UI)。 Task.Delay(500) 的意思是,在 500 毫秒的时间内,告诉别人你已经“完成”了。

因此,不同之处在于,在这 500 毫秒内,此解决方案将允许您的 UI 线程完成所有的内务处理,例如更新屏幕、响应鼠标等,而您的代码有非常重要的 UI 线程去度假(让您的用户界面关闭)。

【讨论】:

  • 您的意思是使用Task.Delay(500) 而不是Task.Wait(500)?即便如此,我不相信这会奏效。
  • 你应该向 OP 解释你的代码。你在 cmets 中写了很多关于保持 OP 简单的文章,但你在这里付出了零努力。
【解决方案3】:

好的,多亏了 Aron,我必须将方法变成异步方法才能使用 await - 现在它可以工作了!我可以在更新 UI 时“等待”。这是编辑后的代码:

    async void move(int floor)
    {
        DateTime now = DateTime.Now;
        TimeSpan duration;
        while (floor > elevator.currentFloor)
        {
            await Task.Delay(500);
            elevator.currentFloor++;
            changeStatus(elevator);
            currentFloorLbl.Text = "Current Floor: " + elevator.currentFloor;
            duration = DateTime.Now - now;
            timeLbl.Text = "Time elapsed: " + duration.TotalMilliseconds.ToString() + "ms";
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-04
    • 1970-01-01
    • 1970-01-01
    • 2018-09-26
    • 1970-01-01
    • 1970-01-01
    • 2020-12-03
    相关资源
    最近更新 更多