Это необходимая сантехника для цикла диспетчера в программе WPF. Он есть у каждой программы с графическим интерфейсом в Windows. Это универсальное решение проблемы между производителем и потребителем. а>. Где ОС и другие программы производят, а поток пользовательского интерфейса вашей программы WPF потребляет. Жесткое требование для приложений с графическим интерфейсом: код библиотеки, реализующий графический интерфейс, никогда не является потокобезопасным. Вы можете легко увидеть цикл здесь, вы не можете увидеть потокобезопасную очередь, которая очищается циклом, она встроена в ОС.
Цикл запускается вызовом Application.Run(). Нелегко увидеть в приложении WPF, в большинстве приложений он создается автоматически из файла App.xaml. Это подталкивает первый «кадр», ваше приложение продолжает работать, пока оно остается внутри цикла. Вы всегда будете видеть его обратно в окне отладчика стека вызовов, когда устанавливаете точку останова в обработчике событий. Закрытие MainWindow вашего приложения является обычным завершением цикла. Что, в свою очередь, вызывает возврат метода Run(), который завершает поток пользовательского интерфейса, который завершает процесс.
Есть несколько сценариев, в которых вы хотели бы иметь вложенный цикл диспетчера. «Модальная петля». Пример такого модального цикла, который вы используете каждый день, — это когда вы щелкаете и перетаскиваете мышью угол окна. Все вводы с помощью мыши и клавиатуры теперь изменяют размер или местоположение окна, они больше не используются для работы с пользовательским интерфейсом в обычном режиме. Отпускание мыши завершает этот цикл. Этот цикл диспетчера встроен в ОС, а не в WPF.
Но WPF также может использовать такой модальный цикл. Каноническим примером является метод Window.ShowDialog()
. Этот метод не возвращает значение, пока диалоговое окно не будет закрыто. Достигается повторным внутренним вызовом WPF PushFrame(). Просто попробуйте это с отладчиком, вы увидите оба вызова PushFrame в окне стека вызовов. Первый — тот, который вызвал ShowDialog(), второй — тот, который вызвал Application.Run(). Вы получите больше, если ваш диалог, в свою очередь, отображает диалоговое окно.
Менее очевидный пример — вызов Dispatcher.Invoke() в потоке пользовательского интерфейса. Метод, который не возвращается, пока не вернется вызванный метод. Обычно это немного ошибка, но не было веских причин для ее запрета. Слово предупреждения может быть уместным, модальные циклы довольно опасны. Они умеют вызывать ошибки повторного входа. Ошибка, из-за которой метод DoEvents() стал таким печально известным. Основная причина, по которой ShowDialog() отключает все остальные окна в вашем пользовательском интерфейсе.
person
Hans Passant
schedule
20.01.2017