在下面的WPF代码中,只有一个按钮和一个标签。我希望这个行为是这样的:我会看到按钮被禁用,并且"做东西"写在标签上,那么用户界面将被冻结。但这种情况并非如此。我甚至没有看到"做东西"标签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;
}
}
}
;
答案 0 :(得分:5)
Thread.Sleep阻塞当前线程 - 在本例中是UI线程 - 意味着不能完成其他任务。 因此,UI线程现在无法执行任何消息,例如刷新屏幕&#39;直到长时间阻止操作完成。
会有一个挂起的消息,如WM_PAINT告诉Windows必须重新绘制UI,但由于线程被Sleep操作阻止,因此无法执行该消息。 如果在Thread.Sleep之前添加以下代码行,您将看到在UI被冻结之前将刷新标签
Application.DoEvents();
请注意,阻止UI线程并调用Application.DoEvents在大多数情况下都不是一个好的解决方案。与阻止UI线程和调用DoEvents相比,更有可能采用更好的方法来解决某个问题。 (例如,使用后台线程或任务来执行长时间运行的操作,并使用事件通知UI该任务的进度)。
永远不要在UI线程上执行长时间运行的任务,因为您的应用程序将无法响应。因此,最好将工作卸载到另一个线程。从.NET 4开始,首选方法是使用TAP(基于任务的异步模式)。
我认为在你的问题中你使用Thread.Sleep来模拟&#39;您想要执行的一些cpu密集型算法。 你可以通过开始一个新的任务来完成这个:
await Task.Run ( () => SomeLongRunningMethod())
答案 1 :(得分:5)
Thread.Sleep
阻止UI线程。声明点击处理程序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;
}