2011-12-15 2 views
3

Я использую wpf, есть кнопка на моем ui.Dispatcher.Invoke из новой темы блокирует мой UI

Когда пользователь нажимает на него, у меня есть цикл for, который запускает новый метод, в новом потоке, используя autoresetevent.

В этом методе в этом новом потоке я использую метку, назовем ее lblStatus. Я хочу обновить этот ярлык в этом потоке, который не находится на ui. используя wpf, я должен использовать Dispatcher.Invoke.

вот пример моего кода:

Thread thread= new Thread(StartLooking); 
thread.Start(); 
_waitHandle.WaitOne(); 

private void StartLooking(object value) 
{ 
if (lblStatus.Dispatcher.Thread == Thread.CurrentThread) 
     { 
      lblStatus.Content = "Scanning>..."; 
     } 
     else 
     { 
      lblStatus.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() => lblStatus.Content = "Scanning>>>>>")); 
     } 
_waitHandle.Set(); 
} 

программа просто останавливается здесь. он не изменяет содержимое метки, он возвращается к моему ui, но блокирует его.
я пытался

lblStatus.Dispatcher.Invoke(DispatcherPriority.Normal, new LblStatusThreadCheck(lblStatusThreadCheck), "Scanning..."); 

, а также, но это не работает также. есть идеи?

+1

Вы думаете об использовании привязки данных? – GETah

+0

Почему вы начинаете новый поток, если хотите дождаться завершения этой операции, прежде чем что-либо можно будет сделать? – whoisthis

ответ

5

Проблема в том, что вы делаете невозможным выполнение этого, поскольку вы используете Invoke.

Dispatcher.Invoke не будет возвращаться до тех пор, пока процесс пользовательского интерфейса не обработает. Тем не менее, вы заблокировали поток пользовательского интерфейса, вызвав _waitHandle.WaitOne(); и не устанавливая дескриптор ожидания, пока ПОСЛЕ этого процесса не будет. Эти два эффективно вызывают мертвую блокировку.

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

0

Вместо этого вы, скорее всего, захотите использовать BeginInvoke. Invoke заблокирует поток, который вызвал его, пока поток пользовательского интерфейса не запустил Action, и поскольку вы устанавливаете приоритет Background, это может занять некоторое время.

2

Поскольку два предыдущих сообщений уже охватывают проблему в коде, просто предложение: вместо

if (lblStatus.Dispatcher.Thread == Thread.CurrentThread) 

попробуйте использовать

if (!lblStatus.CheckAccess()) 

Это чище и имеет точное намерение вы хотите. Просто прочитайте об этом here.