Events
Mar 17, 9 PM - Mar 21, 10 AM
Join the meetup series to build scalable AI solutions based on real-world use cases with fellow developers and experts.
Register nowThis browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Interoperation between the WPF and Windows Forms requires that both technologies have the appropriate keyboard input processing. This topic describes how these technologies implement keyboard and message processing to enable smooth interoperation in hybrid applications.
This topic contains the following subsections:
Modeless Forms and Dialog Boxes
WindowsFormsHost Keyboard and Message Processing
ElementHost Keyboard and Message Processing
Call the EnableWindowsFormsInterop method on the WindowsFormsHost element to open a modeless form or dialog box from a WPF-based application.
Call the EnableModelessKeyboardInterop method on the ElementHost control to open a modeless WPF page in a Windows Forms-based application.
When hosted by a WPF-based application, Windows Forms keyboard and message processing consists of the following:
The WindowsFormsHost class acquires messages from the WPF message loop, which is implemented by the ComponentDispatcher class.
The WindowsFormsHost class creates a surrogate Windows Forms message loop to ensure that ordinary Windows Forms keyboard processing occurs.
The WindowsFormsHost class implements the IKeyboardInputSink interface to coordinate focus management with WPF.
The WindowsFormsHost controls register themselves and start their message loops.
The following sections describe these parts of the process in more detail.
The ComponentDispatcher class implements the message loop manager for WPF. The ComponentDispatcher class provides hooks to enable external clients to filter messages before WPF processes them.
The interoperation implementation handles the ComponentDispatcher.ThreadFilterMessage event, which enables Windows Forms controls to process messages before WPF controls.
By default, the System.Windows.Forms.Application class contains the primary message loop for Windows Forms applications. During interoperation, the Windows Forms message loop does not process messages. Therefore, this logic must be reproduced. The handler for the ComponentDispatcher.ThreadFilterMessage event performs the following steps:
Filters the message using the IMessageFilter interface.
Calls the Control.PreProcessMessage method.
Translates and dispatches the message, if it is required.
Passes the message to the hosting control, if no other controls process the message.
The surrogate message loop handles keyboard management. Therefore, the IKeyboardInputSink.TabInto method is the only IKeyboardInputSink member that requires an implementation in the WindowsFormsHost class.
By default, the HwndHost class returns false
for its IKeyboardInputSink.TabInto implementation. This prevents tabbing from a WPF control to a Windows Forms control.
The WindowsFormsHost implementation of the IKeyboardInputSink.TabInto method performs the following steps:
Finds the first or last Windows Forms control that is contained by the WindowsFormsHost control and that can receive focus. The control choice depends on traversal information.
Sets focus to the control and returns true
.
If no control can receive focus, returns false
.
When the window handle to a WindowsFormsHost control is created, the WindowsFormsHost control calls an internal static method that registers its presence for the message loop.
During registration, the WindowsFormsHost control examines the message loop. If the message loop has not been started, the ComponentDispatcher.ThreadFilterMessage event handler is created. The message loop is considered to be running when the ComponentDispatcher.ThreadFilterMessage event handler is attached.
When the window handle is destroyed, the WindowsFormsHost control removes itself from registration.
When hosted by a Windows Forms application, WPF keyboard and message processing consists of the following:
HwndSource, IKeyboardInputSink, and IKeyboardInputSite interface implementations.
Tabbing and arrow keys.
Command keys and dialog box keys.
Windows Forms accelerator processing.
The following sections describe these parts in more detail.
In Windows Forms, keyboard messages are routed to the window handle of the control that has focus. In the ElementHost control, these messages are routed to the hosted element. To accomplish this, the ElementHost control provides an HwndSource instance. If the ElementHost control has focus, the HwndSource instance routes most keyboard input so that it can be processed by the WPF InputManager class.
The HwndSource class implements the IKeyboardInputSink and IKeyboardInputSite interfaces.
Keyboard interoperation relies on implementing the OnNoMoreTabStops method to handle TAB key and arrow key input that moves focus out of hosted elements.
The Windows Forms selection logic is mapped to the IKeyboardInputSink.TabInto and OnNoMoreTabStops methods to implement TAB and arrow key navigation. Overriding the Select method accomplishes this mapping.
To give WPF the first opportunity to process command keys and dialog keys, Windows Forms command preprocessing is connected to the TranslateAccelerator method. Overriding the Control.ProcessCmdKey method connects the two technologies.
With the TranslateAccelerator method, the hosted elements can handle any key message, such as WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, or WM_SYSKEYUP, including command keys, such as TAB, ENTER, ESC, and arrow keys. If a key message is not handled, it is sent up the Windows Forms ancestor hierarchy for handling.
To process accelerators correctly, Windows Forms accelerator processing must be connected to the WPF AccessKeyManager class. Additionally, all WM_CHAR messages must be correctly routed to hosted elements.
Because the default HwndSource implementation of the TranslateChar method returns false
, WM_CHAR messages are processed using the following logic:
The Control.IsInputChar method is overridden to ensure that all WM_CHAR messages are forwarded to hosted elements.
If the ALT key is pressed, the message is WM_SYSCHAR. Windows Forms does not preprocess this message through the IsInputChar method. Therefore, the ProcessMnemonic method is overridden to query the WPF AccessKeyManager for a registered accelerator. If a registered accelerator is found, AccessKeyManager processes it.
If the ALT key is not pressed, the WPF InputManager class processes the unhandled input. If the input is an accelerator, the AccessKeyManager processes it. The PostProcessInput event is handled for WM_CHAR messages that were not processed.
When the user presses the ALT key, accelerator visual cues are shown on the whole form. To support this behavior, all ElementHost controls on the active form receive WM_SYSKEYDOWN messages, regardless of which control has focus.
Messages are sent only to ElementHost controls in the active form.
.NET Desktop feedback feedback
.NET Desktop feedback is an open source project. Select a link to provide feedback:
Events
Mar 17, 9 PM - Mar 21, 10 AM
Join the meetup series to build scalable AI solutions based on real-world use cases with fellow developers and experts.
Register nowTraining
Module
Develop keyboard-accessible products - Training
Learn how to develop keyboard-accessible products with our comprehensive module. This course covers essential guidelines, design considerations, implementation strategies, and testing methods to ensure your products are accessible to all users, including those with disabilities.