Зачем использовать Dispatcher.BeginInvoke? - PullRequest
4 голосов
/ 12 августа 2011

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

Но я видел примеры, когда в представлении code-behind присваивание свойств, таких как свойство Text для TextBlock, объявляется безопасным, только если вы назначите его в этом Dispatcher.BeginInvoke.

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

В упомянутых выше примерах другие потоки или асинхронные операции не используются.

Вопрос 2 Если у меня есть обработчик асинхронного веб-сервиса, и я хочу обновить строку TextBlock из этого обработчика. Могу ли я напрямую назначить свойство Text TB или использовать Dispatcher.BeginInvoke. Обратите внимание, что я не буду делать это обычно, так как я предпочитаю привязку данных, чем прямые манипуляции с элементами пользовательского интерфейса, подобные этой.

Ответы [ 2 ]

3 голосов
/ 12 августа 2011

Вы спрашиваете "не подразумевается ли, что им манипулируют в потоке пользовательского интерфейса". Ничто не дает абсолютной гарантии, так как Майк указывает, что точки входа не частного кода могут быть вызваны не в потоке пользовательского интерфейса.

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

Что касается принятия любых мер предосторожности для обеспечения работы вашего кода в потоке пользовательского интерфейса, я не думаю, что это разумно. Что произойдет, если вы просто позволите коду работать нормально. Возможно, это удастся, потому что вы на самом деле не взаимодействуете с элементом пользовательского интерфейса, никакого вреда. В качестве альтернативы код продолжается и выдает исключение. Это плохо?

Использование предосторожности BeginInvoke приводит к тому, что вызывающий код завершается асинхронно с вызванным кодом манипулирования пользовательским интерфейсом. Это может привести к непредсказуемому результату, который может стать кошмаром для выслеживания. Намного лучше, чтобы ваш код вел себя предсказуемо. Просто верните ошибку обратно в код, который должен нести ответственность за вызов компонента пользовательского интерфейса в правильном потоке. После того, как весь код выполняется как часть компонента пользовательского интерфейса, такого как UserControl или Page.

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

Редактировать: ответ на дерзкое добавление второстепенного вопроса

Это зависит от используемого вами Async API и от того, в каком потоке был вызван API.

Когда вы вызываете асинхронный метод WebClient из потока пользовательского интерфейса, соответствующее событие также возникает в потоке пользовательского интерфейса. Аналогичным образом, если вы используете клиентский класс службы WCF, событие Completed будет вызываться в потоке пользовательского интерфейса, если асинхронная операция первоначально вызывается в потоке пользовательского интерфейса.

Однако при использовании пар Begin / End в компоненте WebRequest (или стандартном интерфейсе службы из WCF) обратные вызовы будут выполняться в фоновом потоке независимо от исходного потока, использованного для запуска операции.

0 голосов
/ 12 августа 2011

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

...