Windows Forms and WPF Interoperability Input Architecture
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
Modeless Forms and Dialog Boxes
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.
WindowsFormsHost Keyboard and Message Processing
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.
Acquiring Messages from the Windows Presentation Foundation Message Loop
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.
Surrogate Windows Forms Message Loop
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.
IKeyboardInputSink Implementation
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.
WindowsFormsHost Registration
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.
ElementHost Keyboard and Message Processing
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.
Interface Implementations
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.
Tabbing and Arrow Keys
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.
Command Keys and Dialog Box Keys
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.
Accelerator Processing
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.
See Also
Concepts
Walkthrough: Hosting a Windows Forms Composite Control in Windows Presentation Foundation
Walkthrough: Hosting a Windows Presentation Foundation Control in Windows Forms
WPF and Win32 Interoperation Overview