Compartilhar via


Arquitetura de entrada para interoperabilidade entre Windows Forms e WPF

Interoperabilidade entre WPF e Windows Forms requer que as duas tecnologias tenham o processamento de entrada de teclado apropriado. Este tópico descreve como essas tecnologias implementam processamento de teclado e de mensagens para permitir uma suave interoperação em aplicativos híbridos.

Este tópico contém as subseções a seguir:

  • Formulários sem janela restrita de mudança de foco e caixas de diálogo

  • Processamento de teclado e de mensagens pelo WindowsFormsHost

  • Processamento de teclado e de mensagens pelo ElementHost

Chame o método EnableWindowsFormsInterop no elemento WindowsFormsHost para abrir um formulário ou caixa de diálogo sem janela restrita de mudança de foco de um aplicativo baseado em WPF.

Chame o método EnableModelessKeyboardInterop no controle ElementHost para abrir uma página WPF sem janela restrita de mudança de foco em um aplicativo com base em Windows Forms.

Processamento de teclado e de mensagens pelo WindowsFormsHost

Quando hospedado por um aplicativo WPF, o processamento de teclado e de mensagens Windows Forms consiste de:

As seções a seguir descrevem essas partes do processo em mais detalhes.

Aquisição de mensagens do loop de mensagens do Windows Presentation Foundation

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 do WPF processá-las.

A implementação de interoperação trata o evento ComponentDispatcher.ThreadFilterMessage, o qual permite que os controles Windows Forms processem mensagens antes dos controles WPF.

Loop de mensagens Windows Forms substituto

Por padrão, a classe System.Windows.Forms.Application contém o loop de mensagens principal para aplicativos Windows Forms. Durante a interoperação, o loop de mensagens Windows Forms não processa mensagens. Portanto, essa lógica deve ser reproduzida. O manipulador para o evento ComponentDispatcher.ThreadFilterMessage executa os seguintes passos:

  1. Filtra a mensagem usando a interface IMessageFilter.

  2. Chama o método Control.PreProcessMessage.

  3. Converte e despacha a mensagem, se for necessário.

  4. Passa a mensagem para o controle hospedeiro, se não houverem outros controles que processem a mensagem.

Implementação do IKeyboardInputSink

O loop de mensagens substituto trata do gerenciamento de teclado. Portanto, o método IKeyboardInputSink.TabInto é o único membro de 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 que se passe de um controle WPF para um controle Windows Forms usando a tecla TAB.

A implementação de WindowsFormsHost do método IKeyboardInputSink.TabInto executa as seguintes etapas:

  1. Localiza o primeiro ou último controle Windows Forms que está contido no controle WindowsFormsHost e que possa receber o foco. A opção de que controle selecionar depende de informações de percorrimento.

  2. Define o foco para o controle e retorna true.

  3. Se nenhum controle pode receber o foco, retorna false.

Registro de um WindowsFormsHost

Quando o manipulador de janela de um controle 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 mensagens. Se o loop de mensagem não foi iniciado, o manipulador de eventos ComponentDispatcher.ThreadFilterMessage será criado. Se considera que o loop de mensagens está sendo executado quando o manipulador de eventos ComponentDispatcher.ThreadFilterMessage está anexado.

Quando o manipulador de janela é destruído, o controle WindowsFormsHost remove a si próprio do registro.

Processamento de teclado e de mensagens pelo ElementHost

Quando hospedado por um aplicativo Windows Forms, o processamento de teclado e de mensagens WPF consiste de:

As seções a seguir descrevem essas partes com mais detalhes.

Implementações de interfaces

Em Windows Forms, mensagens de teclado são roteadas para o manipulador de janela do controle que tem o foco. No controle ElementHost, essas mensagens são roteadas para o elemento hospedado. Para fazer isso, o controle ElementHost fornece uma instância de HwndSource. Se o controle ElementHost tiver o foco, a instância HwndSource roteia a maioria das entradas de teclado de modo que possam ser processadas pela classe InputManager do WPF.

A classe HwndSource implementa as interfaces IKeyboardInputSink e IKeyboardInputSite.

A interoperação de teclado depende de implementa-ser o método OnNoMoreTabStops para tratar pressionamentos da tecla TAB e das teclas de direção que movam o foco para fora dos elementos hospedados.

Teclas de direção e de tabulação.

A lógica de seleção do Windows Forms é mapeada para os métodos IKeyboardInputSink.TabInto e OnNoMoreTabStops para implementar navegação pela tecla TAB e pelas teclas de direção. A substituição do método Select realiza esse mapeamento.

Para dar a primeira oportunidade ao WPF de processar teclas de comando e de caixas de diálogo, o pré-processamento de comandos do Windows Forms é conectado ao método TranslateAccelerator. A substituição do método Control.ProcessCmdKey conecta as duas tecnologias.

Com o método TranslateAccelerator, os elementos hospedados podem manipular qualquer mensagem de teclas, como WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN ou WM_SYSKEYUP, incluindo as teclas de comando como TAB, ENTER, ESC e teclas de direção. Se uma mensagem de tecla não é lida, ela é enviada para aos predecessores do Windows Forms na hierarquia para manipulação.

Processamento de aceleradores

Para processar aceleradores corretamente o processamento de aceleração do Windows Forms deve estar conectado à classe AccessKeyManager do WPF. Além disso, todas as mensagens WM_CHAR devem ser roteadas corretamente para os elementos hospedados.

Como a implementação padrão do método TranslateChar de HwndSource retorna false, as mensagens WM_CHAR são processadas usando a seguinte lógica:

  • O método Control.IsInputChar é substituído para garantir que todas as mensagens WM_CHAR são encaminhadas para elementos hospedados.

  • Se a tecla ALT for pressionada, a mensagem é WM_SYSCHAR. Windows Forms não pré-processar esta mensagem por meio do IsInputChar método. Portanto, o método ProcessMnemonic é substituído para consultar o AccessKeyManager do WPF para um acelerador registrado. Se um acelerador registrado for encontrado, o AccessKeyManager o processará.

  • Se a tecla ALT não estiver pressionada, a classe InputManager do WPF processa a entrada não tratada. Se a entrada é um acelerador, o AccessKeyManager a processará. O evento PostProcessInput é tratado para mensagens WM_CHAR que não foram processadas.

Quando o usuário pressiona a tecla ALT, dicas visuais de aceleração são mostradas no formulário inteiro. Para dar suporte a esse comportamento todos os controles ElementHost no formulário ativo recebem mensagens WM_SYSKEYDOWN, independentemente de que controle tem o foco.

As mensagens são enviadas somente a controles ElementHost no formulário ativo.

Consulte também

Conceitos

Demonstra Passo a passo: Hospedagem de um controle composto do Windows Forms no Windows Presentation Foundation

Demonstra Passo a passo: Hospedagem de um controle Windows Presentation Foundation no Windows Forms

Visão geral sobre interoperabilidade entre WPF e Win32

Referência

EnableWindowsFormsInterop

EnableModelessKeyboardInterop

ElementHost

WindowsFormsHost