2014-12-17 9 views
0

В приложении WPF (C#, .NET 4.0, VS 2013), следующий код (вызывается из UI потока) замерзает UI нить в течение 1 секунды:замерзает UI темы, пока он не должен быть

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

Thread.Sleep() является заполнителем. В фактическом коде он получит доступ к некоторому элементу пользовательского интерфейса и сделает небольшой расчет времени. Это также работает на потоке пользовательского интерфейса!

Не следует ли его запускать в другом потоке, кроме потока пользовательского интерфейса? Что я пропустил?

+0

Вы используете диспетчер для выполнения действия в потоке пользовательского интерфейса, и он блокируется на секунду. – Samuel

+0

Обратите внимание, что доступ к пользовательскому интерфейсу из фонового потока вызовет исключение. Обновления элементов пользовательского интерфейса должны выполняться в основном потоке, и для этого вы можете использовать Dispatcher.BeginInvoke (...). – Onots

ответ

4

Dispatcher.BeginInvoke предназначен для толкания операций (через делегат) на резьбу пользовательского интерфейса. У вас есть , чтобы нажать Thread.Sleep(1000) на поток пользовательского интерфейса, так что да: поток пользовательского интерфейса замерзнет.

From MSDN

Например, фоновый поток, который отделился от основного потока пользовательского интерфейса не может обновить содержимое Баттона, который был создан в потоке пользовательского интерфейса. Чтобы фоновый поток мог получить доступ к свойству Content Button, фоновый поток должен делегировать работу диспетчеру, связанному с потоком пользовательского интерфейса. Это достигается с помощью Invoke или BeginInvoke. Invoke является синхронным, а BeginInvoke является асинхронным.

Если вы хотите, чтобы сделать работу в фоновом режиме ... вы уже были на фоне потока (перед вызовом Dispatcher.BeginInvoke).

Я подозреваю, что вы должны делать здесь:

  1. использование .Invoke для сбора значений из пользовательского интерфейса в рабочий
  2. сделать обработку на рабочий
  3. использование .Invoke или .BeginInvoke обновить UI
+0

Спасибо. Я склонен забывать о цели Dispatcher.BeginInvoke/Invoke. :( – Donotalo

1

Dispatcher.BeginInvoke выполняет операции над основным потоком. Используйте это, чтобы выполнить на вашу тему:

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

как Марк уже сказал Dispatcher.BeginInvoke() выталкивает весь код Int действия на UI Thread поэтому код запускается на выполнение там, если вы хотите, чтобы ваш пользовательский интерфейс, чтобы оставаться отзывчивым , выполните вычисления, прежде чем вы вызовете Dispatcher.Begin Invoke, а затем настройте элементы управления пользовательским интерфейсом в BeginInvoke.

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

Или взглянуть на async-await выполнять методы Asynchron и не утруждая с UI threadsynchronization себя. Simple Example

Смежные вопросы