WPF: проблема обновления пользовательского интерфейса из фонового потока - PullRequest
3 голосов
/ 18 мая 2010

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

                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 (), то сообщения о состоянии обновляются правильно.

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

Спасибо.

Ответы [ 3 ]

6 голосов
/ 18 мая 2010

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, которое связано с триггером для рассматриваемых элементов пользовательского интерфейса, но это другая история ...

РЕДАКТИРОВАТЬ: Как вариант, вы можете извлечь класс BackgroundWorker , который содержит ProgressChanged и RunWorkerCompleted события, которые автоматически запускаются в главном потоке.

4 голосов
/ 18 мая 2010
fThread.IsBackground = true;
fThread.Start();

fThread.Join();

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

РЕДАКТИРОВАТЬ: Причина, по которой это работает, если вы отображаете окно сообщения между вызовами Start и Join, состоит в том, что тогда основной поток выполняет цикл сообщений для окна сообщения, а не блокируется при вызове Join.

1 голос
/ 18 мая 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...