Обеспечение запуска в потоке пользовательского интерфейса в WPF - PullRequest
35 голосов
/ 04 марта 2010

Я создаю приложение WPF. Я делаю асинхронную связь со стороной сервера и использую агрегацию событий с Prism на клиенте. Обе эти вещи приводят к появлению новых потоков, которые не являются потоком пользовательского интерфейса. Если я попытаюсь выполнить «операции WPF» на этих потоках обратного вызова и обработчика событий, мир развалится, что он теперь начал делать.

Сначала я столкнулся с проблемами при попытке создать некоторые объекты WPF в обратном вызове с сервера. Мне сказали, что поток должен работать в режиме STA. Теперь я пытаюсь обновить некоторые данные пользовательского интерфейса в обработчике событий Prism, и мне говорят, что:

Вызывающий не может получить доступ к этому потоку, поскольку он принадлежит другому потоку.

Итак, в чем ключ к правильной работе в WPF? Я читал об Диспетчере WPF в этом сообщении MSDN . Я начинаю понимать, но я еще не волшебник.

  1. Ключ всегда используется Dispatcher.Invoke, когда мне нужно запустить что-то, что, я не уверен, будет вызвано в потоке пользовательского интерфейса?
  2. Имеет ли значение, если он действительно вызывался в потоке пользовательского интерфейса, и я все равно делаю Dispatcher.Invoke?
  3. Dispatcher.Invoke = синхронно. Dispathcher.BeginInvoke = async?
  4. Будет ли Dispatcher.Invoke запрашивать поток пользовательского интерфейса, а затем перестанет его ждать? Это плохая практика и риск менее отзывчивых программ?
  5. Как мне получить диспетчер? Будет ли Dispatcher.CurrentDispatcher всегда давать мне диспетчер, представляющий поток пользовательского интерфейса?
  6. Будет ли существовать более одного Dispatcher или «Dispatcher» в основном совпадает с потоком пользовательского интерфейса для приложения?
  7. А что за дело с BackgroundWorker? Когда я использую это вместо? Я полагаю, это всегда асинхронно?
  8. Будет ли все, что выполняется в потоке пользовательского интерфейса (вызывается), выполняться в режиме квартиры STA? То есть если у меня есть что-то, что требует запуска в режиме STA - будет ли достаточно Dispatcher.Invoke?

Кто-нибудь хочет прояснить для меня вещи? Любые связанные рекомендации и т. Д.? Спасибо!

1 Ответ

37 голосов
/ 05 марта 2010

Переходя к каждому из ваших вопросов, один за другим:

  1. Не совсем; Вы должны вызывать поток UI только при необходимости. Смотрите # 2.
  2. Да, это важно. Вы не должны просто автоматически Invoke все. Ключ должен вызывать поток UI только при необходимости. Для этого вы можете использовать метод Dispatcher.CheckAccess .
  3. Это правильно.
  4. Также правильно, и да, вы рискуете стать менее отзывчивыми программами. В большинстве случаев вы не будете смотреть на серьезное снижение производительности (мы говорим о миллисекундах для переключения контекста), но вы должны только Invoke, если это необходимо. При этом, в некоторых случаях это неизбежно, поэтому нет, я бы не сказал, что это плохая практика вообще. Это всего лишь одно решение проблемы, с которой вы будете сталкиваться время от времени.
  5. В каждом случае, который я видел, я делал должное с Dispatcher.CurrentDispatcher. Для сложных сценариев этого может быть недостаточно, но я (лично) их не видел.
  6. Не совсем правильно, но такое мышление не принесет никакого вреда. Позвольте мне выразиться так: Dispatcher может использоваться для получения доступа к потоку пользовательского интерфейса для приложения. Но это не само по себе поток пользовательского интерфейса.
  7. BackgroundWorker обычно используется, когда у вас трудоемкая операция и вы хотите поддерживать отзывчивый пользовательский интерфейс во время выполнения этой операции в фоновом режиме. Обычно вы не используете BackgroundWorker вместо Invoke, скорее вы используете BackgroundWorker в сочетании с Invoke. То есть, если вам нужно обновить какой-либо объект пользовательского интерфейса в вашем BackgroundWorker, вы можете вызвать его в потоке пользовательского интерфейса, выполнить обновление и затем вернуться к исходной операции.
  8. Да. Поток пользовательского интерфейса приложения WPF по определению должен выполняться в однопоточной квартире.

Многое можно сказать о BackgroundWorker, я уверен, что многие вопросы уже посвящены этому, поэтому я не буду вдаваться в подробности. Если вам интересно, посмотрите страницу MSDN для класса BackgroundWorker .

...