Arquitetura de entrada de interoperabilidade do Windows Forms e WPF
A interoperação entre o WPF e o Windows Forms requer que ambas as tecnologias tenham o processamento de entrada de teclado apropriado. Este tópico descreve como essas tecnologias implementam o processamento de teclado e mensagens para habilitar a interoperação suave em aplicativos híbridos.
Este tópico contém as seguintes subseções:
Formulários não Modais e Caixas de Diálogo
Processamento de mensagens e teclado do WindowsFormsHost
Processamento de mensagens e teclado ElementHost
Formulários Sem Moldura e Caixas de Diálogo
Chame o método EnableWindowsFormsInterop no elemento WindowsFormsHost para abrir um formulário de modelagem ou caixa de diálogo de um aplicativo baseado em WPF.
Chame o método EnableModelessKeyboardInterop no controle ElementHost para abrir uma página do WPF modeless em um aplicativo baseado em Windows Forms.
Processamento de mensagens e teclado do WindowsFormsHost
Quando hospedado por um aplicativo baseado em WPF, o processamento de mensagens e o teclado do Windows Forms consistem no seguinte:
A classe WindowsFormsHost adquire mensagens do loop de mensagens do WPF, que é implementado pela classe ComponentDispatcher.
A classe WindowsFormsHost cria um loop de mensagem alternativo do Windows Forms para garantir que o processamento de teclado comum do Windows Forms ocorra.
A classe WindowsFormsHost implementa a interface IKeyboardInputSink para coordenar o gerenciamento de foco com o WPF.
Os controles WindowsFormsHost se registram e iniciam os loops de mensagem.
As seções a seguir descrevem essas partes do processo com mais detalhes.
Adquirindo mensagens do Loop de Mensagens do WPF
A classe ComponentDispatcher implementa o gerenciador de loop de mensagens para WPF. A classe ComponentDispatcher fornece ganchos para permitir que clientes externos filtrem mensagens antes que o WPF as processe.
A implementação de interoperação manipula o evento ComponentDispatcher.ThreadFilterMessage, que permite que os controles do Windows Forms processem mensagens antes dos controles do WPF.
Loop de mensagens substituto dos Windows Forms
Por padrão, a classe System.Windows.Forms.Application contém o loop de mensagem principal para aplicativos do Windows Forms. Durante a interoperação, o loop de mensagens do Windows Forms não processa mensagens. Portanto, essa lógica deve ser reproduzida. O manipulador do evento ComponentDispatcher.ThreadFilterMessage executa as seguintes etapas:
Filtra a mensagem usando a interface IMessageFilter.
Chama o método Control.PreProcessMessage.
Converte e expedi a mensagem, se ela for necessária.
Passa a mensagem para o controle de hospedagem, se nenhum outro controle processar a mensagem.
Implementação de IKeyboardInputSink
O loop de mensagem alternativa manipula o gerenciamento de teclado. Portanto, o método IKeyboardInputSink.TabInto é o único membro IKeyboardInputSink que requer uma implementação na classe WindowsFormsHost.
Por padrão, a classe HwndHost retorna false
para sua implementação de IKeyboardInputSink.TabInto. Isso impede a tabulação de um controle WPF para um controle do Windows Forms.
A implementação WindowsFormsHost do método IKeyboardInputSink.TabInto executa as seguintes etapas:
Localiza o primeiro ou último controle do Windows Forms contido no controle WindowsFormsHost e que pode receber o foco. A escolha do controle depende de informações de percurso.
Define o foco para o controle e retorna
true
.Se nenhum controle puder receber o foco, retorna
false
.
Registro do WindowsFormsHost
Quando o identificador de janela para um controle do tipo WindowsFormsHost é criado, o controle WindowsFormsHost chama um método estático interno que registra sua presença no loop de mensagens.
Durante o registro, o controle WindowsFormsHost examina o loop de mensagem. Se o loop de mensagem não tiver sido iniciado, o manipulador de eventos ComponentDispatcher.ThreadFilterMessage será criado. O loop de mensagem é considerado em execução quando o manipulador de eventos ComponentDispatcher.ThreadFilterMessage é anexado.
Quando o identificador da janela é destruído, o controle WindowsFormsHost se remove automaticamente do registro.
Processamento de mensagens e teclado ElementHost
Quando hospedado por um aplicativo do Windows Forms, o processamento de teclado e mensagem do WPF consiste no seguinte:
implementações de interface HwndSource, IKeyboardInputSinke IKeyboardInputSite.
Teclas de direção e tecla Tab.
Teclas de comando e teclas de caixa de diálogo.
Processamento de acelerador do Windows Forms.
As seções a seguir descrevem essas partes com mais detalhes.
Implementações de interface
Nos Windows Forms, as mensagens de teclado são roteadas para o identificador de janela do controle que tem foco. No controle ElementHost, essas mensagens são roteadas para o elemento hospedado. Para fazer isso, o controle ElementHost fornece uma instância HwndSource. Se o controle ElementHost tiver foco, a instância HwndSource roteia a maior parte da entrada do teclado para que possa ser processada pela classe InputManager WPF.
A classe HwndSource implementa as interfaces IKeyboardInputSink e IKeyboardInputSite.
A interoperação de teclado depende da implementação do método OnNoMoreTabStops para lidar com a entrada da tecla TAB e das teclas de seta que movem o foco para fora dos elementos hospedados.
Teclas tabbing e seta
A lógica de seleção do Windows Forms é mapeada para os métodos IKeyboardInputSink.TabInto e OnNoMoreTabStops para implementar a navegação com TAB e teclas de seta. Sobrescrever o método Select executa esse mapeamento.
Teclas de comando e teclas de caixa de diálogo
Para dar ao WPF a primeira oportunidade de processar chaves de comando e chaves de diálogo, o pré-processamento de comando do Windows Forms está conectado ao método TranslateAccelerator. Sobrescrever o método Control.ProcessCmdKey conecta as duas tecnologias.
Com o método TranslateAccelerator, os elementos hospedados podem lidar com qualquer mensagem de chave, como WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN ou WM_SYSKEYUP, incluindo chaves de comando, como teclas TAB, ENTER, ESC e seta. Se uma mensagem chave não for tratada, ela será enviada para a hierarquia ancestral do Windows Forms para manipulação.
Processamento de acelerador
Para processar aceleradores corretamente, o processamento de aceleradores do Windows Forms deve estar ligado à classe AccessKeyManager WPF. Além disso, todas as mensagens WM_CHAR devem ser roteadas corretamente para elementos hospedados.
Como a implementação de HwndSource padrão do método TranslateChar retorna false
, WM_CHAR mensagens são processadas usando a seguinte lógica:
O método Control.IsInputChar é substituído para garantir que todas as mensagens WM_CHAR sejam encaminhadas para elementos hospedados.
Se a tecla ALT for pressionada, a mensagem será WM_SYSCHAR. O Windows Forms não pré-processa essa mensagem por meio do método IsInputChar. Portanto, o método ProcessMnemonic é substituído para consultar o AccessKeyManager do WPF para um acelerador registrado. Se um acelerador registrado for encontrado, AccessKeyManager processá-lo-á.
Se a tecla ALT não for pressionada, a classe InputManager WPF processará a entrada sem tratamento. Se a entrada for um acelerador, o AccessKeyManager processa. O evento PostProcessInput é tratado para mensagens WM_CHAR que não foram processadas.
Quando o usuário pressiona a tecla ALT, as indicações visuais do acelerador são mostradas em todo o formulário. Para dar suporte a esse comportamento, todos os controles ElementHost presentes no formulário ativo recebem mensagens WM_SYSKEYDOWN, independentemente de qual controle esteja com o foco.
As mensagens são enviadas apenas para controles de ElementHost no formulário ativo.
Consulte também
.NET Desktop feedback