Вызов control.BeginInvoke () помещает передаваемый вами делегат во внутреннюю очередь и вызывает PostMessage (), чтобы пробудить цикл обработки сообщений и обратить внимание.Это то, что запускает первый BeginInvoke.Любые входные события (мышь и клавиатура) также попадают в очередь сообщений, Windows помещает их туда.
Поведение, на которое вы не рассчитывали, заключается в коде, который запускается при получении отправленного сообщения.Он не просто удаляет из очереди один запрос вызова и выполняет его, он зацикливается, пока вся очередь вызова не будет очищена.Как работает ваш код, эта очередь никогда не очищается, потому что вызов ContinueWith () добавляет еще один запрос вызова.Таким образом, он просто продолжает циклически обрабатывать запросы на вызовы и никогда не получает возможность получать больше сообщений из очереди сообщений.Или, другими словами: это прокачивает очередь вызовов, а не очередь сообщений.
Входящие сообщения остаются в очереди сообщений до тех пор, пока ваш код не прекратит добавлять дополнительные запросы, и регулярная закачка цикла сообщений не возобновится,после того, как ваш код перестает повторяться.Ваш интерфейс будет выглядеть замороженным, пока это происходит, потому что события Paint также не доставляются.Они генерируются только тогда, когда очередь сообщений пуста.
Важно, чтобы она работала так, как работает, вызов PostMessage () не гарантированно работает.Windows не допускает более 10 000 сообщений в очереди сообщений.Но Control.BeginInvoke () не имеет такого ограничения.При полном опустошении очереди вызовов потерянное сообщение PostMessage не вызывает никаких проблем.Это поведение вызывает другие проблемы, хотя.Классический слишком часто вызывает BackgroundWorker.ReportProgress ().Такое же поведение, поток пользовательского интерфейса просто залит запросами вызова и больше не справляется со своими обычными обязанностями.Нахмурившись на любого, кто сталкивается с этим: «Я использую BackgroundWorker, но мой пользовательский интерфейс все еще зависает».
В любом случае, ваш эксперимент - ужасная ошибка.Вызов Application.DoEvents () потребуется для принудительного освобождения очереди сообщений.Много предостережений с этим, проверьте этот ответ для деталей.Предстоящая поддержка ключевого слова async предоставит еще один способ сделать это.Не уверен, что он по-другому обрабатывает приоритет сообщения.Я скорее сомневаюсь, что Control.BeginInvoke () довольно ядро.Одним из способов решения проблемы является использование таймера с очень коротким интервалом.Сообщения таймера также попадают в очередь сообщений (вроде), но имеют очень низкий приоритет.Входные события обрабатываются первыми.Или низкоуровневый хак: вызов PostMessage со своим собственным сообщением и переопределение WndProc для его обнаружения.Это становится немного прямолинейным и узким.Событие Application.Idle полезно для обработки после получения любых входных событий.