Thread.Sleep背后的逻辑[重复]

问题描述 投票:0回答:2

这个问题在这里已有答案:

在下面的WPF代码中,只有一个按钮和一个标签。我希望行为是这样的:我会看到按钮被禁用,标签上写着“Doing Stuff”,然后会冻结那个用户界面。但这种情况并非如此。我甚至没有看到“Doing Stuff”标签UI被冻结到开头。你能告诉我这背后的逻辑吗?为什么Thread.Sleep会让UI立即冻结?

using System.Threading.Tasks;
using System.Threading;
using System.Windows;

namespace MessagePump
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void btnDoStuff_Click(object sender, RoutedEventArgs e)
    {
        btnDoStuff.IsEnabled = false;
        lblStatus.Content = "Doing Stuff";
        Thread.Sleep(4000);
        lblStatus.Content = "Not doing anything";
        btnDoStuff.IsEnabled = true;
    }
}
}
;
c# wpf
2个回答
5
投票

Thread.Sleep阻塞当前线程 - 在本例中是UI线程 - 意味着不能完成其他任务。因此,UI线程现在无法执行任何消息,如“刷新屏幕”,直到长时间阻止操作完成。

将有一个挂起的消息,如WM_PAINT告诉Windows必须重新绘制UI,但由于线程被Sleep操作阻止,因此无法执行该消息。如果在Thread.Sleep之前添加以下代码行,您将看到在UI被冻结之前将刷新标签

Application.DoEvents();

请注意,阻止UI线程并调用Application.DoEvents在大多数情况下并不是一个好的解决方案。与阻止UI线程和调用DoEvents相比,更有可能采用更好的方法来解决某个问题。 (例如,使用后台线程或任务来执行长时间运行的操作并使用事件来通知UI该任务的进度)。

永远不要在UI线程上执行长时间运行的任务,因为您的应用程序将无响应。因此,最好将工作卸载到另一个线程。从.NET 4开始,首选方法是使用TAP(基于任务的异步模式)。

我认为在你的问题中你使用Thread.Sleep来“模拟”你想要执行的一些cpu密集型算法。你可以通过启动一个新的任务来完成这个:

await Task.Run ( () => SomeLongRunningMethod())

5
投票

Thread.Sleep阻止UI线程。声明Click处理程序async并调用Task.Delay

private async void btnDoStuff_Click(object sender, RoutedEventArgs e)
{
    btnDoStuff.IsEnabled = false;
    lblStatus.Content = "Doing Stuff";

    await Task.Delay(4000);

    lblStatus.Content = "Not doing anything";
    btnDoStuff.IsEnabled = true;
}
© www.soinside.com 2019 - 2024. All rights reserved.