Поделиться через


Совместное использование циклов обработки сообщений между Win32 и WPF

Обновлен: Ноябрь 2007

Этот раздел описывает, как реализовать цикл обработки сообщений для взаимодействия с Windows Presentation Foundation (WPF) при помощи существующего доступа к циклу обработки сообщений в Dispatcher или при помощи создания отдельного цикла обработки сообщения на стороне Win32 вашего кода взаимодействия.

Диспетчер компонента и цикл обработки сообщений

Обычный сценарий для взаимодействия и поддержки события клавиатуры является реализация IKeyboardInputSink или подкласса из классов, в которых уже реализован IKeyboardInputSink, таких как HwndSource или HwndHost. Тем не менее, поддержка приемника клавиатуры не обращается ко всем возможным циклам обработки сообщений при отправке и получении сообщений через ваши границы взаимодействия. Чтобы помочь формализовать архитектуру цикла обработки сообщений приложения, Windows Presentation Foundation (WPF) предоставляет класс ComponentDispatcher, который определяет простой протокол для выполнения цикла обработки сообщений.

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

ComponentDispatcher предоставляет события, которые могут прослушивать другие компоненты (такие как приемник клавиатуры). Класс Dispatcher вызывает соответствующие методы ComponentDispatcher в соответствующей последовательности. При реализации вашего собственного цикла обработки сообщений, ваш код ответственен за вызов методов ComponentDispatcher аналогичным образом.

Вызов методов ComponentDispatcher в потоке только вызовет обработчики событий, которые были зарегистрированы в этом потоке.

Написание Циклов Обработки Сообщений

Ниже приведен список членов ComponentDispatcher которые вы будете использовать при написании собственного цикла обработки сообщений:

  • PushModal: ваш цикл обработки сообщений должен вызывать его для того, чтобы показать, что поток является модальным.

  • PopModal: ваш цикл обработки сообщений должен вызывать его для того, чтобы показать, что поток стал немодальным.

  • RaiseIdle: ваш цикл обработки сообщений должен вызывать его для того, чтобы показать, что ComponentDispatcher должен вызвать событие ThreadIdle. ComponentDispatcher не вызовет ThreadIdle если IsThreadModal является true, но циклы обработки сообщений могут вызвать RaiseIdle, даже если ComponentDispatcher не может отвечать на него, пока находится в модальном состоянии.

  • RaiseThreadMessage: ваш цикл обработки сообщений должны вызывать его для того, чтобы показать, что доступно новое сообщение. Возвращаемое значение указывает на то, обработал ли слушатель события ComponentDispatcher сообщение. Если RaiseThreadMessage возвращает true(обработано), то диспетчер в дальнейшем ничего не делает с сообщением. Если возвращаемое значение равно false, то диспетчер ожидает вызов Win32 функции TranslateMessage, и затем вызывает DispatchMessage.

Использование Диспетчера Компонента и Обработки Существующих Сообщений

Ниже приведен список членов ComponentDispatcher которые вы будете использовать во встроенном WPF цикле обработки сообщений:

  • IsThreadModal: определяет, является ли приложение модальным (например, был помещен модальный цикл обработки сообщений).ComponentDispatcher может отслеживать это состояние, так как класс содержит счетчик вызовов PushModal и PopModal из цикла обработки сообщений.

  • События ThreadFilterMessage и ThreadPreprocessMessage соответствуют стандартным правилам для вызова делегата. Делегаты вызываются в неопределенном порядке, и все делегаты вызываются, даже если первый из них помечает сообщение как обработанное.

  • Событие ThreadIdle: указывает подходящее и эффективное время для фоновой обработки (когда нет других ожидающих сообщений для потока).ThreadIdle не вызывается, если поток является модальным.

  • ThreadFilterMessage: вызывается для всех сообщений, что сообщение загружает процессы.

  • ThreadPreprocessMessage: вызывается для всех сообщений, которые не были обработаны во время ThreadFilterMessage.

Сообщение считается обработанным, если после события ThreadFilterMessage или события ThreadPreprocessMessage параметр handled, передаваемый по ссылке в данных события, равен true. Обработчики событий должны игнорировать сообщение, если handled равен true, так как это означает, что другой обработчик обработал сообщение первым. Обработчики событий могут изменить сообщение для обоих событий. Диспетчер должен отправлять измененное сообщение, а не исходное.ThreadPreprocessMessage доставляется всем слушателям, но архитектурно необходимо только верхнеуровневое окно, содержащее HWND, у которого нужные сообщения должны вызвать код в ответ на сообщение.

Как HwndSource Рассматривает События Диспетчера Компонента

Если HwndSource является окном верхнего уровня (нет родительского HWND), оно будет зарегистрировано с ComponentDispatcher. Если вызывается ThreadPreprocessMessage, и если сообщение предназначено для HwndSource или дочерних окон, HwndSource вызывает его последовательность приемника клавиатуры IKeyboardInputSink.TranslateAccelerator, TranslateChar, OnMnemonic.

Если HwndSource не является окном верхнего уровня (имеет родителя HWND), оно обработано не будет. Только окно верхнего уровня ожидает выполнения обработки и оно должно быть окном верхнего уровня с поддержкой приемника клавиатуры в качестве части любого сценария взаимодействия.

Если WndProc в HwndSource вызывается без соответствующего вызова метода приемника клавиатуры, ваше приложение получит более высокоуровневые события клавиатуры, такие как KeyDown. Однако не будут вызваны такие методы приемника клавиатуры, которые нарушают возможности модели ввода клавиатуры, такие как поддержка клавиш доступа. Это может произойти, поскольку цикл обработки сообщений не уведомил соответствующий поток на ComponentDispatcher, или поскольку родительское HWND не вызвало соответствующие ответы приемника клавиатуры.

Сообщение, которое переходит приемнику клавиатуры не может быть отправлено HWND, если вы добавили ловушки для этого сообщения с помощью метода AddHook. Сообщение может быть непосредственно обработано на уровне загрузки сообщений и не отправлено функции DispatchMessage.

См. также

Основные понятия

Общие сведения о взаимодействии WPF и Win32

Модель потоков

Общие сведения о входных данных

Ссылки

ComponentDispatcher

IKeyboardInputSink