Вы не должны добавить блокировку. Запросы Dispatcher.Invoke и BeginInvoke не будут запускаться в середине другого кода (это и есть их смысл).
всего две вещей, чтобы рассмотреть следующие вопросы:
- BeginInvoke может быть более подходящим в данном случае, Invoke в очереди запроса, а затем блокировать вызывающую нить, пока интерфейс не бездействует и заканчивает выполнение кода, BeginInvoke будет только очередь запроса без блокировки.
- Некоторые операции, особенно операции, открывающие окна (в том числе сообщения) или межпроцессные коммуникации, могут позволить запускать операции очереди в диспетчере.
EDIT: первый, у меня нет ссылок, потому что страницы MSDN на эту тему, к сожалению, очень мало подробностей - но я написал тестовые программы, чтобы проверить поведение BeginInvoke и все, что я пишу здесь, является результатом этих испытаний.
Теперь, чтобы развернуть вторую точку, нам сначала нужно понять, что делает диспетчер. Очевидно, это очень упрощенное объяснение.
Любой пользовательский интерфейс Windows работает путем обработки сообщений; Например, когда пользователь перемещает мышь над окном, система отправляет это сообщение WM_MOUSEMOVE.
Система отправляет сообщение, добавляя его в очередь, каждый поток может иметь очередь, все окна, созданные одним и тем же потоком, имеют одну и ту же очередь.
В основе каждой программы Windows лежит цикл «цикл сообщения» или «насос сообщений», этот цикл считывает следующее сообщение из очереди и вызывает соответствующий код окна для обработки этого сообщения.
В WPF этот цикл и вся соответствующая обработка обрабатываются диспетчером.
Приложение может либо находиться в очереди сообщений, ожидая следующего сообщения, либо может что-то сделать. Вот почему, когда у вас длинный расчет, все окна потока становятся невосприимчивыми - поток занят работой и не возвращается в цикл сообщения для обработки следующего сообщения.
Dispatcher.Invoke и BeginInvoke работает путем очередности запрошенной операции и выполнения ее в следующий раз, когда поток возвращается в цикл сообщения.
Вот почему Dispatcher. (Begin) Invoke не может «ввести» код в середине вашего метода, вы не вернетесь в цикл сообщения, пока ваш метод не вернется.
НО
Любой код может запустить цикл обработки сообщений. Когда вы вызываете все, что запускает цикл сообщения, Dispatcher вызывается и может запускать операции (Begin) Invoke.
Какой код имеет контур сообщения?
- Все, что имеет графический интерфейс или что excepts пользовательского ввода, например, диалоговые окна, окна сообщений, перетащить & падение и т.д. - если таковые не имеют цикл обработки сообщений, чем приложение было бы отвечать на запросы и не в состоянии обрабатывать ввод пользователя.
- Связь между процессами, использующая сообщения Windows за кулисами (большинство методов взаимодействия между процессами, включая COM, используют их).
- Любое другое, что занимает много времени и не затормозит систему (быстрый, что система не заморожена, является доказательством ее обработки сообщений).
Итак, подведем итоги:
- диспетчеру не может просто бросить код в ваш поток, он может выполнять только код, когда приложение находится в «цикл обработки сообщений».
- Любой код, который вы пишете, не имеет петель сообщений, если вы их явно не написали.
- Большинство UI-кода не имеют собственного цикла сообщений, например, если вы вызываете Window.Show, а затем выполняете длинный расчет, окно появляется только после завершения вычисления и возврата метода (и приложение возвращается к цикл сообщений и обрабатывает все сообщения, необходимые для открытия и рисования окна).
- Но любой код, который взаимодействует с пользователем перед его возвратом (MessageBox.Show, Window.ShowDialog), должен иметь контур сообщения.
- В некотором коде коммуникации (сети и между процессами) используются петли сообщений, а некоторые нет, в зависимости от конкретной реализации, которую вы используете.
Не могли бы вы немного рассказать о своем втором пункте, пожалуйста, что такое опасный сценарий? – mcintyre321
Цитаты тоже были бы хороши. –
Хорошо, я добавил короткий (всего в 6 раз больше, чем оригинальный ответ) объяснение того, как и когда Dispatcher. (Begin) Invoke работает. – Nir