Arquitectura de entrada de interoperabilidad entre formularios Windows Forms y WPF

La interoperación entre WPF y Windows Forms requiere que ambas tecnologías tengan el procesamiento de entrada de teclado adecuado. En este tema se describe cómo estas tecnologías implementan el procesamiento de mensajes y teclado para habilitar la interoperación fluida en aplicaciones híbridas.

Este tema contiene las siguientes subsecciones:

  • Cuadros de diálogo y formularios no modales

  • Procesamiento de mensajes y teclado de WindowsFormsHost

  • Procesamiento de mensajes y teclado de ElementHost

Cuadros de diálogo y formularios no modales

Llame al método EnableWindowsFormsInterop en el elemento WindowsFormsHost para abrir un cuadro de diálogo o formulario no modal desde una aplicación basada en WPF.

Llame al método EnableModelessKeyboardInterop en el control ElementHost para abrir una página de WPF no modal en una aplicación basada en Windows Forms.

Procesamiento de mensajes y teclado de WindowsFormsHost

Cuando se hospeda en una aplicación basada en WPF, el procesamiento del teclado de Windows Forms y de mensajes consta de lo siguiente:

Las siguientes secciones describen estos elementos y procesos con mayor detalle.

Adquisición de mensajes del bucle de mensajes de WPF

La clase ComponentDispatcher implementa el administrador de bucles de mensajes para WPF. La clase ComponentDispatcher proporciona enlaces para permitir que los clientes externos filtren los mensajes antes de que WPF los procese.

La implementación de interoperación controla el evento ComponentDispatcher.ThreadFilterMessage, lo que permite que los controles de Windows Forms procesen mensajes antes de los controles de WPF.

Suplencia del bucle de mensajes de Windows Forms

De forma predeterminada, la clase System.Windows.Forms.Application contiene el bucle de mensajes principal para aplicaciones Windows Forms. Durante la interoperación, el bucle de mensajes de Windows Forms no procesa los mensajes. Por lo tanto, esta lógica debe reproducirse. El controlador del evento ComponentDispatcher.ThreadFilterMessage realiza los pasos siguientes:

  1. Filtra el mensaje mediante la interfaz IMessageFilter.

  2. Llama al método Control.PreProcessMessage.

  3. Traduce y envía el mensaje, si fuera necesario.

  4. Pasa el mensaje al control de hospedaje, si ningún otro control procesa el mensaje.

Implementación de IKeyboardInputSink

El bucle de mensajes suplente controla la administración del teclado. Por lo tanto, el método IKeyboardInputSink.TabInto es el único miembro IKeyboardInputSink que requiere una implementación en la clase WindowsFormsHost.

De forma predeterminada, la clase HwndHost devuelve false para su implementación de IKeyboardInputSink.TabInto. Esto evita la tabulación de un control de WPF a un control de Windows Forms.

La implementación de WindowsFormsHost del método IKeyboardInputSink.TabInto realiza los pasos siguientes:

  1. Busca el primer o último control de Windows Forms que contiene el control WindowsFormsHost y que puede recibir el foco. La elección del control depende de la información transversal.

  2. Establece el foco en el control y devuelve true.

  3. Si ningún control puede recibir el foco, devuelve false.

Registro de WindowsFormsHost

Cuando se crea el identificador de ventana para un control WindowsFormsHost, el control WindowsFormsHost llama a un método estático interno que registra su presencia para el bucle de mensajes.

Durante el registro, el control WindowsFormsHost examina el bucle de mensajes. Si no se ha iniciado el bucle de mensajes, se crea el controlador de eventos ComponentDispatcher.ThreadFilterMessage. El bucle de mensajes se considera que se está ejecutando cuando se adjunta el controlador de eventos ComponentDispatcher.ThreadFilterMessage.

Cuando se destruye el identificador de ventana, el control WindowsFormsHost se quita del registro.

Procesamiento de mensajes y teclado de ElementHost

Cuando se hospeda en una aplicación de Windows Forms, el procesamiento del teclado de WPF y de mensajes consta de lo siguiente:

En las secciones siguientes se describen estos elementos con más detalle.

Implementaciones de interfaces

En Windows Forms, los mensajes de teclado se enrutan al identificador de ventana del control que tiene el foco. En el control ElementHost, estos mensajes se enrutan al elemento hospedado. Para ello, el control ElementHost proporciona una instancia de HwndSource. Si el control ElementHost tiene el foco, la instancia de HwndSource enruta la mayoría de las entradas de teclado para que la clase InputManager de WPF pueda procesarla.

La clase HwndSource implementa las interfaces IKeyboardInputSink y IKeyboardInputSite.

La interoperación de teclado se basa en la implementación del método OnNoMoreTabStops para controlar la tecla TAB y la entrada de tecla de dirección que mueve el foco fuera de los elementos hospedados.

Tabulación y teclas de dirección

La lógica de selección de Windows Forms se asigna a los métodos IKeyboardInputSink.TabInto y OnNoMoreTabStops para implementar la navegación con tabulación y tecla de dirección. La invalidación del método Select realiza esta asignación.

Teclas de comando y teclas de cuadro de diálogo

Para dar a WPF la primera oportunidad de procesar las teclas de comando y las teclas de diálogo, el preprocesamiento de comandos de Windows Forms está conectado al método TranslateAccelerator. Al invalidar el método Control.ProcessCmdKey se conectan las dos tecnologías.

Con el método TranslateAccelerator, los elementos hospedados pueden controlar cualquier mensaje de tecla, como WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN o WM_SYSKEYUP, incluidas las teclas de comando, como TAB, ENTRAR, ESC y teclas de dirección. Si no se controla un mensaje de tecla, se enviará para que ascienda por la jerarquía de Windows Forms para poder controlarse.

Procesamiento del acelerador

Para procesar los aceleradores correctamente, el procesamiento del acelerador de Windows Forms debe estar conectado a la clase AccessKeyManager de WPF. Además, todos los mensajes WM_CHAR deben enrutarse correctamente a los elementos hospedados.

Dado que la implementación predeterminada de HwndSource del método TranslateChar devuelve false, los mensajes WM_CHAR se procesan mediante la lógica siguiente:

  • El método Control.IsInputChar se invalida para asegurarse de que todos los mensajes WM_CHAR se reenvía a los elementos hospedados.

  • Si se presiona la tecla ALT, el mensaje es WM_SYSCHAR. Windows Forms no preprocesa este mensaje mediante el método IsInputChar. Por lo tanto, el método ProcessMnemonic se invalida para consultar a AccessKeyManager de WPF para un acelerador registrado. Si se encuentra un acelerador registrado, AccessKeyManager lo procesa.

  • Si no se presiona la tecla ALT, la clase InputManager de WPF procesa la entrada no controlada. Si la entrada es un acelerador, AccessKeyManager la procesa. El evento PostProcessInput se controla para mensajes WM_CHAR que no se procesaron.

Cuando el usuario presiona la tecla ALT, las indicaciones visuales del acelerador se muestran en todo el formulario. Para admitir este comportamiento, todos los controles ElementHost del formulario activo reciben mensajes WM_SYSKEYDOWN, independientemente del control que tenga el foco.

Los mensajes solo se envían a los controles ElementHost en el formulario activo.

Vea también