Este artigo foi traduzido por máquina. Para visualizar o arquivo em inglês, marque a caixa de seleção Inglês. Você também pode exibir o texto Em inglês em uma janela pop-up, movendo o ponteiro do mouse sobre o texto.
Tradução
Inglês

Interoperação Win32 e WPF

 

Publicado: junho de 2016

Este tópico fornece uma visão geral de como interoperar WPF e Win32 código.Windows Presentation Foundation (WPF) Fornece um ambiente sofisticado para criação de aplicativos. No entanto, quando você tem um investimento substancial em Win32 código, pode ser mais eficiente reutilizar parte desse código.

Há duas técnicas básicas de interoperação entre WPF e Win32 código.

  • Host WPF conteúdo em um Win32 janela. Com essa técnica, você pode usar os recursos avançados de elementos gráficos do WPF dentro da estrutura de um padrão Win32 janela e aplicativo.

  • Host um Win32 janela no WPF conteúdo. Com essa técnica, você pode usar um arquivo custom Win32 controle no contexto de outros WPF conteúdo e passar dados entre os limites.

Cada uma dessas técnicas é apresentada conceitualmente neste tópico. Para obter uma ilustração mais orientada a código de hospedagem WPF em Win32, consulte Passo a passo: Hospedando conteúdo WPF em Win32. Para obter uma ilustração mais orientada a código de hospedagem Win32 em WPF, consulte Passo a passo: Hospedando um controle Win32 no WPF.

WPF APIs código gerenciado, mas a maioria existentes Win32 programas são escritos em não gerenciada C++. Não é possível chamar WPF APIs de um verdadeiro não o programa.  No entanto, usando o /clr opção com o Microsoft Visual C++ compilador, você poderá criar um misto gerenciado onde você pode misturar perfeitamente gerenciados e não gerenciados API chamadas.

Uma complicação no nível de projeto é que você não pode compilar Extensible Application Markup Language (XAML) arquivos em uma C++ projeto. Há várias técnicas de divisão de projeto para compensar isso.

  • Criar um C# DLL que contém todos os seus XAML páginas como um assembly compilado e faça com que seu C++ executável incluem DLL como uma referência.

  • Criar um C# executável para o WPF de conteúdo e a referência a um C++ DLL que contém o Win32 conteúdo. 

  • Use Load para carregar qualquer XAML em tempo de execução, em vez de compilar seu XAML.

  • Não use XAML e gravar todas as suas WPF no código, construir a árvore de elementos de Application.

Use qualquer abordagem funciona melhor para você.

System_CAPS_noteObservação

Se você não usou C++/CLI antes, você poderá notar algumas palavras-chave "new", como gcnew e nullptr nos exemplos de código de interoperação. Essas palavras-chave substituem a antiga sintaxe com sublinhado duplo (__gc) e fornecem uma sintaxe mais natural para código gerenciado em C++. Para saber mais sobre o C++/CLI recursos gerenciados, consulte extensões de componentes para plataformas de tempo de execução e Olá c++ CLI.

Para obter o máximo de WPF "Interoperabilidade HWND", você precisa entender como WPF usa HWNDs. Para qualquer HWND, você não pode misturar WPF renderização com DirectX renderização ou GDI / GDI+ renderização. Isso tem várias implicações. Basicamente, para misturar esses modelos de renderização todo, você deve criar uma solução de interoperabilidade e usar segmentos de interoperação designados para cada modelo de renderização que você optar por usar. Além disso, o comportamento de renderização cria uma restrição de "espaço aéreo" para o que sua solução de interoperação pode realizar. O conceito de "espaço aéreo" é explicado com mais detalhes no tópico Visão geral da tecnologia regiões.

Todos os WPF elementos na tela, por fim, contam com um HWND. Quando você cria um WPF Window, WPF cria um HWND de alto nível e usa um HwndSource para colocar o Window e sua WPF conteúdo dentro do HWND.  O restante do seu WPF conteúdo no aplicativo compartilha aquele único HWND. Uma exceção é menus suspensos de caixa de combinação e demais pop-ups. Esses elementos criam sua própria janela de nível superior, razão pela qual um WPF menu potencialmente pode passar da borda da janela HWND que a contém. Quando você usa HwndHost para colocar um HWND dentro de WPF, WPF informa Win32 como posicionar o novo filho HWND relativo para o WPF Window HWND. 

Um conceito relacionado a HWND é transparência dentro e entre cada HWND. Isso também é discutido no tópico Visão geral da tecnologia regiões.

A chave para hospedar um WPF em um Win32 janela é o HwndSource classe. Essa classe encapsula a WPF conteúdo em um Win32 janela, para que o WPF conteúdo pode ser incorporado ao seu user interface (UI) como uma janela filho. A abordagem a seguir combina a Win32 e WPF em um único aplicativo.

  1. Implementar o WPF conteúdo (o elemento conteúdo raiz) como uma classe gerenciada. Normalmente, a classe herda de uma das classes que podem conter vários elementos filho e/ou usado como um elemento raiz, como DockPanel ou Page. Nas etapas subseqüentes, essa classe é conhecida como o WPF classe de conteúdo e instâncias da classe são denominados WPF objetos de conteúdo.

  2. Implementar um Win32 aplicativo com C++/CLI. Se você estiver começando com um existente não gerenciado C++ aplicativo, você normalmente poderá habilitá-lo a chamar código gerenciado alterando as configurações de projeto para incluir o /clr Sinalizador do compilador (o escopo completo do que pode ser necessário para oferecer suporte a /clr compilação não é descrita neste tópico).

  3. Defina o modelo de threading para Single Threaded Apartment (STA).WPF usa esse modelo de threading.

  4. Trate a notificação WM_CREATE no seu procedimento de janela.

  5. Dentro do manipulador (ou uma função que chama o identificador), faça o seguinte:

    1. Criar um novo HwndSource objeto com o HWND da janela pai como seu parent parâmetro.

    2. Criar uma instância do seu WPF classe de conteúdo.

    3. Atribua uma referência para o WPF objeto de conteúdo para o HwndSource objeto RootVisual propriedade.

    4. O HwndSource objeto Handle propriedade contém o identificador de janela (HWND). Para obter um HWND que você pode usar na parte não gerenciada de seu aplicativo, converta Handle.ToPointer() para um HWND.

  6. Implemente uma classe gerenciada que contenha um campo estático que contém uma referência ao seu WPF objeto de conteúdo. Essa classe permite que você obtenha uma referência para o WPF objeto de conteúdo de seu Win32 código, mas mais importante-impede que o HwndSource seja inadvertidamente coletado como lixo.

  7. Receber notificações do WPF objeto conteúdo anexando um manipulador a um ou mais o WPF eventos de objeto de conteúdo.

  8. Se comunicar com o WPF o objeto de conteúdo usando a referência que você armazenou no campo estático para definir propriedades, chamar métodos, etc.

System_CAPS_noteObservação

Você pode fazer algumas ou todas as WPF conteúdo a definição de classe do passo 1 em XAML usando a classe parcial padrão da classe de conteúdo, se você gerar um assembly separado e, em seguida, fazer referência a ela. Embora você normalmente inclue uma Application objeto como parte da compilação do XAML em um assembly, você acaba não usando Application como parte da interoperação, simplesmente use um ou mais das classes raiz para XAML arquivos chamados pelo aplicativo e referencia suas classes parciais. O restante do procedimento é essencialmente similar ao descrito acima.

Cada uma dessas etapas é ilustrada através de código no tópico Passo a passo: Hospedando conteúdo WPF em Win32.

A chave para hospedar uma Win32 janela dentro dos outros WPF conteúdo é o HwndHost classe. Essa classe encapsula a janela em um WPF elemento que pode ser adicionado a um WPF árvore de elementos. HwndHost também oferece suporte a APIs que permitem executar tarefas, como processar mensagens para a janela hospedada. O procedimento básico é:

  1. Criar uma árvore de elemento para uma WPF aplicativo (pode ser por meio de código ou marcação). Localize um ponto adequado e apropriado na árvore de elementos onde a HwndHost implementação pode ser adicionada como um elemento filho. No restante dessas etapas, esse elemento é chamado de elemento de reserva.

  2. Derivar de HwndHost para criar um objeto que contém o Win32 conteúdo.

  3. Na classe host, sobrescreva o HwndHost método BuildWindowCore. Retorne o HWND da janela hospedada. Talvez você queira ajustar o controle real como uma janela filho da janela retornada; envolver os controles em uma janela host fornece uma maneira simples para seu WPF conteúdo para receber notificações dos controles. Essa técnica ajuda a corrigir alguns Win32 problemas em relação ao tratamento de mensagens no limiar do controle hospedado.

  4. Substituir o HwndHost métodos DestroyWindowCore e WndProc. A intenção aqui é processar a limpeza e remover referências ao conteúdo hospedado, especialmente se você tiver criado referências a objetos não gerenciados.

  5. No seu arquivo code-behind, crie uma instância da classe que hospeda controles e torne-a um filho do elemento de reserva. Normalmente você usaria um manipulador de eventos, como Loaded, ou use o construtor de classe parcial. Mas você também pode adicionar o conteúdo de interoperação através de um comportamento de tempo de execução.

  6. Processo selecionado mensagens de janela, como notificações de controle. Há duas abordagens. Ambos fornecem acesso idêntico ao fluxo de mensagens, portanto sua escolha é principalmente uma questão de conveniência de programação.

    • Mensagem implementam processamento de todas as mensagens (não apenas mensagens de desligamento) em seu substituto do HwndHost método WndProc.

    • Ter a hospedagem WPF elemento processar as mensagens manipulando o MessageHook evento. Esse evento é gerado para cada mensagem que é enviada para o procedimento de janela principal da janela hospedada.

    • Você não pode processar as mensagens de janelas que estão fora do processo usando WndProc.

  7. Comunicar-se com a janela hospedada usando platform invoke para chamar não gerenciado SendMessage função.

Essas etapas a seguir cria um aplicativo que funciona com a entrada do mouse. Você pode adicionar suporte a TAB para sua janela hospedada Implementando a IKeyboardInputSink interface.

Cada uma dessas etapas é ilustrada através de código no tópico Passo a passo: Hospedando um controle Win32 no WPF.

Você pode pensar HwndHost como um controle especial. (Tecnicamente, HwndHost é um FrameworkElement derivado de classe, não um Control classe derivada, mas ele pode ser considerado um controle para fins de interoperação.) HwndHost abstrai a Win32 natureza do conteúdo hospedado, de forma que o restante do WPF considera o conteúdo hospedado como outro objeto tipo controle, que deve renderizar e processar entrada. HwndHost geralmente se comporta como qualquer outro WPF FrameworkElement, mas há algumas diferenças importantes em torno de saída (desenho e elementos gráficos) e pode oferecer suporte a entrada (mouse e teclado) com base nas limitações de que os HWNDs subjacentes. 

  • FrameworkElement, que é o HwndHost classe base, tem muito poucas propriedades que implicam alterações na interface do usuário. Estas incluem propriedades como FrameworkElement.FlowDirection, que altera o layout dos elementos que têm esse elemento como pai. No entanto, a maioria dessas propriedades não é mapeada para possível Win32 equivalentes, mesmo se tais equivalentes podem existir. Muitas dessas propriedades e seus significados são específicas de tecnologia de processamento muito para mapeamentos sejam práticos. Portanto, definir propriedades como FlowDirection em HwndHost não tem nenhum efeito.

  • HwndHost não pode ser girado, dimensionado, inclinado ou caso contrário afetado por uma transformação.

  • HwndHost não oferece suporte a Opacity propriedade (combinação alfa). Se o conteúdo dentro do HwndHost executa System.Drawing operações que incluem informações de alfa, que não é uma violação, mas o HwndHost como um todo só oferece suporte a opacidade = 1,0 (100%).

  • HwndHost aparecerá sobre outro WPF elementos na mesma janela de nível superior. No entanto, um ToolTip ou ContextMenu menu gerado é uma janela de alto nível separada e assim irão se comportar corretamente com HwndHost.

  • HwndHost não respeita a região de recorte de seu pai UIElement. É possível que haja um problema se você tentar colocar um HwndHost classe dentro de uma região de rolagem ou Canvas.

  • Em geral, enquanto os dispositivos de entrada tem escopo dentro do HwndHost hospedado Win32 região, eventos de entrada vão diretamente para Win32.

  • Enquanto o mouse está sobre o HwndHost, seu aplicativo não receberá WPF eventos de mouse e o valor da WPF propriedade IsMouseOver será false.

  • Enquanto o HwndHost tem o foco do teclado, seu aplicativo não receberá WPF eventos e o valor de teclado do WPF propriedade IsKeyboardFocusWithin será false.

  • Quando o foco está dentro do HwndHost e muda para outro controle dentro a HwndHost, seu aplicativo não receberá o WPF eventos GotFocus ou LostFocus.

  • Relacionados à caneta propriedades e eventos são análogos e não relatam informações enquanto a caneta está sobre HwndHost.

O IKeyboardInputSink e IKeyboardInputSite interfaces permitem que você crie uma experiência de teclado uniforme para misto WPF e Win32 aplicativos:

  • Tabulações entre Win32 e WPF componentes

  • Mnemônicos e aceleradores que funcionam quando o foco está em um componente Win32 e quando ele estiver em um componente WPF.

O HwndHost e HwndSource classes fornecem implementações de IKeyboardInputSink, mas elas podem não tratar todas as mensagens de entrada que você deseje em cenários mais avançados. Substitua os métodos apropriados para obter o comportamento de teclado desejado.

As interfaces somente oferecem suporte para o que acontece na transição entre o WPF e Win32 regiões. Dentro de Win32 região, comportamento de tabulação é totalmente controlado pelo Win32 implementado lógica, se houver.

Mostrar: