2010-05-18 5 views
3

В моем коде запускается фоновый поток. Фоновый поток вносит изменения и хочет, чтобы пользовательский интерфейс в основном потоке обновлялся. Код, который запускает поток затем ждет выглядит что-то вроде:WPF: выпуск обновления интерфейса из фоновой темы

   Thread fThread = new Thread(new ThreadStart(PerformSync)); 

       fThread.IsBackground = true; 
       fThread.Start(); 

       fThread.Join(); 

       MessageBox.Show("Synchronization complete"); 

Когда фон хочет обновить пользовательский интерфейс, он устанавливает StatusMessage и называет код ниже:

static StatusMessage _statusMessage; 
    public delegate void AddStatusDelegate(); 
    private void AddStatus() 
    { 
     AddStatusDelegate methodForUIThread = delegate 
     { 
      _statusMessageList.Add(_statusMessage); 
     }; 

     this.Dispatcher.BeginInvoke(methodForUIThread, System.Windows.Threading.DispatcherPriority.Send); 
    } 

_statusMessageList является ObservableCollection, что является источником для ListBox.

Вызывается метод AddStatus, но код в основном потоке никогда не выполняется - то есть _statusMessage не добавляется в _statusMessageList во время выполнения потока. Однако, как только он будет завершен (fThread.Join() возвращает), выполняются все уложенные вызовы в основном потоке.

Но, если я покажу окно сообщений между вызовами fThread.Start() и fThread.Join(), сообщения о состоянии обновляются соответствующим образом.

Что нужно изменить, чтобы код в основном потоке выполнялся (обновления пользовательского интерфейса) в ожидании завершения потока?

Спасибо.

ответ

4
fThread.IsBackground = true; 
fThread.Start(); 

fThread.Join(); 

Звонок в Join() блокирует вашу основную нить до тех пор, пока фоновый поток не завершится. Таким образом, поток пользовательского интерфейса не может ничего сделать, пока работает другой поток. Вам не нужно звонить Join(). Если вам нужно что-то сделать в главном потоке после окончания фонового потока, найдите другой способ сделать это.

EDIT: Причина, по которой он работает, если вы видите окно сообщения между вызовом Start и Join, потому что тогда основной поток запускает цикл сообщения для окна сообщения, а не блокируется при вызове Join.

6

fThread.Join заставляет основной поток блокироваться до тех пор, пока фоновый поток не завершится. Пока основной поток заблокирован, пользовательский интерфейс не может быть обновлен.

Что вам нужно сделать, это что-то вроде этого (непроверенные, но вы должны получить идею):

void someUiEventThatCausesTheBackgroundProcessingToStart() { 
    Thread fThread = new Thread(new ThreadStart(PerformSync)); 
    fThread.IsBackground = true; 

    // disable some UI components here, so that the user cannot 
    // start the thread a second time 
    ... 

    fThread.Start(); 

    // *don't* call Thread.Join here, so that your main thread does not block! 
} 

void PerformSync() { 
    try { 
     // do your stuff here 
     ... 
    } finally { 
     Dispatcher.Invoke(new Action(ProcessingDone)); 
    } 
} 

void ProcessingDone() { 
    // re-enable the UI components 
    ... 

    MessageBox.Show("Synchronization complete"); 
} 

Конечно, в WPF, отключение/включение компонентов пользовательского интерфейса идеально сделано с помощью некоторого свойства IsBusyProcessing зависимостей который связан с триггером к элементам пользовательского интерфейса в вопросе, но это уже другая история ...

EDIT: Как еще один вариант, вы можете check outBackgroundWorker класса, который содержит ProgressChanged и RunWorkerCompleted события, которые автоматически стрелять в основной тр объявление.

1

BackgroundWorker является правильным инструментом для этой работы. Это не сложнее, чем это абсолютно необходимо, дает вам все необходимые для выполнения отчетов задачи, и есть много информации (например, this answer) о том, как ее использовать.

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