Для чего нужен PushFrame?

Я столкнулся с методом PushFrame объекта Dispatcher. Это упрощенная версия метода:

public void PushFrame(DispatcherFrame frame)
{
    // Stuff
    _frameDepth++;

    while(frame.Continue)
    {
        // Getting and dispatching messages
    }

    _frameDepth--;
    // Stuff
}

Другими словами, он просто открывает новый цикл обработки сообщений. Но я действительно не могу понять преимущества такого способа. Для каких целей используется PushFrame? Есть ли хорошие примеры его использования? Как по мне, так этот способ приведет к не очевидным ошибкам.


person LmTinyToon    schedule 20.01.2017    source источник
comment
msdn.microsoft.com/en-us/ библиотека/   -  person Chandan Rai    schedule 20.01.2017
comment
Я читаю документацию. Я знаю, как это работает, но я не могу понять цели этого метода. Зачем нужен метод PushFrame   -  person LmTinyToon    schedule 20.01.2017


Ответы (2)


Это необходимая сантехника для цикла диспетчера в программе 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
comment
Отличное объяснение. Спасибо - person LmTinyToon; 20.01.2017
comment
Два вопроса: • Блокирует ли PushFrame выполнение — так что любой процесс во время выполнения этого фрейма должен выполняться в отдельном потоке? • Приведет ли это к тому, что приложение останется отзывчивым, пока кадр продолжается (DispatcherFrame.Continue == true)? - person Adam L. S.; 05.08.2019

Для каких целей используется PushFrame?

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

Понимание очереди диспетчера

Есть ли хорошие примеры его использования?

Например, когда вы по какой-то причине хотите синхронно вызвать асинхронный метод и продолжать качать сообщения, пока задача не завершится. Вы найдете конкретный пример реализации этого в библиотеке AsyncCTPUtil Стивена Клири на GitHub: https://github.com/StephenCleary/AsyncCTPUtil/blob/master/AsyncTestUtilities/WpfContext.cs

Пожалуйста, обратитесь к его ответу здесь для получения дополнительной информации:

Как мне запустить асинхронный метод Task‹T› синхронно?< /а>

Вы также можете обратиться к следующей ссылке: метод-во время ожидания-асинхронного-метода-для-завершения?forum=wpf" rel="nofollow noreferrer">https://social.msdn.microsoft.com/Forums/vstudio/en-US/650e69f9-5f4d -4d77-8107-93fb6646f26d/решенный-блок-синхронный-метод-в-ожидании-асинхронного-метода-завершения?forum=wpf

person mm8    schedule 20.01.2017