UI线程冻结,但它不应该冻结

时间:2014-12-17 08:05:12

标签: c# .net wpf multithreading

在WPF应用程序(C#,.NET 4.0,VS 2013)中,以下代码(从UI线程调用)冻结UI线程1秒钟:

new Thread(new ThreadStart(() =>
{
    Dispatcher.BeginInvoke(new Action(() =>
    {
        Thread.Sleep(1000);
    }));
})).Start();

Thread.Sleep()是一个占位符。在实际代码中,它将访问一些UI元素并进行一些耗时的计算。这也在UI线程上运行!

它不应该在UI线程以外的其他线程中运行吗?我错过了什么?

3 个答案:

答案 0 :(得分:4)

Dispatcher.BeginInvoke 旨在将操作(通过委托)推送到UI线程。你已经告诉它Thread.Sleep(1000)推送到UI线程,所以是的:UI线程将冻结。

From MSDN

  

例如,从主UI线程分离出来的后台线程无法更新在UI线程上创建的Button的内容。为了让后台线程访问Button的Content属性,后台线程必须将工作委托给与UI线程关联的Dispatcher。这是通过使用Invoke或BeginInvoke来完成的。 Invoke是同步的,Be​​ginInvoke是异步的。

如果您想在后台完成工作...... 您已经在后台线程(在致电Dispatcher.BeginInvoke之前)。

我怀疑你在这里应该做的是:

  1. 使用.Invoke从UI收集值到工作人员
  2. 对工作人员进行处理
  3. 使用.Invoke.BeginInvoke更新用户界面

答案 1 :(得分:1)

Dispatcher.BeginInvoke在主线程上执行操作。使用它来执行你的线程:

    new Thread(new ThreadStart(() =>
    {
        {
            Thread.Sleep(1000);
        };
    })).Start();

答案 2 :(得分:1)

就像Marc已经说Dispatcher.BeginInvoke()将Action中的所有代码都推送到UI线程所以如果你希望你的UI保持响应,代码就会在那里执行,在你调用Dispatcher.Begin Invoke之前执行计算然后在BeginInvoke中设置UI控件。

new Thread(new ThreadStart(() =>
{
    int result = MyHeavyCalculation();
    Dispatcher.BeginInvoke(new Action(() =>
    {
        label1.Text = result.ToString();
    }));
})).Start();

或者看看async-await以异步方式执行方法,而不必为自己的UI线程同步而烦恼。 Simple Example

相关问题