Мой поток пользовательского интерфейса заблокирован при ожидании Dispatcher.BeginInvoke (с использованием WPF и WCF)

У меня есть окно WPF, которое создает и запускает таймер в своем конструкторе. Событие истечения таймера запускает метод (SyncPTUpdate), который использует BeginInvoke для вызова другого метода (PTProgressUpdateInThread) в потоке окна. Затем это вызывает вызов WCF асинхронно (с использованием шаблона TAP, автоматически сгенерированного VS 2013).

Когда я искусственно увеличиваю продолжительность вызова WCF (используя thread.sleep в серверном компоненте), пользовательский интерфейс моего приложения WPF зависает. Не сразу, а через несколько секунд.

Где я ошибаюсь?

public delegate void PTProgressDelegate();

// this method is called from a periodically firing timer (System.Timers)
private async void SyncPTUpdate(object sender, ElapsedEventArgs e)
{
    await this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new PTProgressDelegate(PTProgressUpdateInThread));
}

private async void PTProgressUpdateInThread()
{
    PTMapFieldClient = new FieldClient();
    ServiceField.BlokPTProgress PTProgressFromServer = await PTMapFieldClient.GetPTProgressAsync(variousparametershere);
    PTMapFieldClient.Close();

    // now use the results of the WCF call to update the Window UI
    //...
}

person FalconRime    schedule 04.02.2014    source источник
comment
Кстати, используйте делегата System.Action.   -  person SLaks    schedule 05.02.2014
comment
Почему вы вообще работаете в потоке пользовательского интерфейса?   -  person SLaks    schedule 05.02.2014
comment
Вы имеете в виду, почему я запускаю таймер в потоке окна? Хороший вопрос, только потому, что я из однопоточной культуры и только медленно осваиваю многопоточность. Я думал, что новый таймер все равно породил новый поток?   -  person FalconRime    schedule 05.02.2014
comment
Вы можете использовать System.Windows.Threading.DispatcherTimer, если хотите, чтобы ваш таймер срабатывал в основном потоке.   -  person Sebastian Negraszus    schedule 05.02.2014
comment
Похоже, зависание пользовательского интерфейса может быть вызвано вашими комментариями. // now use the results of the WCF call to update the Window UI   -  person Stephen Cleary    schedule 05.02.2014
comment
Создайте правильную ViewModel, которая использует Application.Current.BeginInvoke() для NotifyPropertChanged(), и все ваши проблемы волшебным образом исчезнут.   -  person Federico Berasategui    schedule 05.02.2014
comment
@StephenCleary Хорошая идея, но я знаю, что зависание не вызвано этим, потому что это происходит только тогда, когда я помещаю thread.sleep в свой код wcf на сервере, а не в клиентский код выше.   -  person FalconRime    schedule 05.02.2014
comment
@HighCore Спасибо, не знаю, что это такое, но выясню.   -  person FalconRime    schedule 05.02.2014
comment
@FalconRime: попробуйте заменить вызов службы на Task.Delay и создать воспроизводимый тестовый пример.   -  person Stephen Cleary    schedule 05.02.2014


Ответы (1)


Dispatcher.BeginInvoke() часто представляют как способ делать что-то асинхронно, с тем преимуществом, что не нужно создавать/задействовать другой поток.

Но это означает, что это полезно только для небольших и легких работ. Лучше всего здесь отправить вызов(ы) PTProgressUpdateInThread() в ThreadPool. Или используйте многопотоковый таймер.
Вы все равно не используете результаты после await.

person Henk Holterman    schedule 04.02.2014
comment
Спасибо, посмотрю, как отправить задание в ThreadPool. Обновил мой код, чтобы показать, что результаты ожидания используются для обновления пользовательского интерфейса окна (следовательно, я полагаю, что он нужен в потоке окна). - person FalconRime; 05.02.2014
comment
Ваше решение сработало для меня, спасибо. В конце концов я реализовал это, чтобы перенести рабочую нагрузку на другой поток. Thread MyNewThread = new Thread(new ThreadStart(() =› { this.Dispatcher.BeginInvoke(new Action(() =› { PTProgressUpdateInThread(PTProgress); })); // передаем полученные данные в поток пользовательского интерфейса } ) ); МойНовыйПоток.Начать(); - person FalconRime; 06.02.2014