Incorporando um Navegador Chromium em Aplicações WPF com C#

Introdução à Integração de Conteúdo Web no WPF

A necessidade de integrar capacidades de navegação web modernas e ricas em funcionalidades diretamente em aplicações desktop é cada vez mais comum. Frameworks como o Windows Presentation Foundation (WPF) oferecem uma base robusta para a UI, mas a exibição de conteúdo web complexo, como JavaScript avançado ou HTML5, pode ser um desafio com o controle WebBrowser nativo, que geralmente se baseia em versões antigas do Internet Explorer.

Para superar essas limitações, desenvolvedores .NET podem recorrer a bibliotecas de terceiros que empacotam motores de navegador modernos. Uma solução popular é o CefSharp, que permite incorporar uma versão do navegador Chromium (o mesmo motor que alimenta o Google Chrome) diretamente em aplicações C# WPF.

Configurando o Ambiente de Desenvolvimento

Para começar a usar o CefSharp no seu projeto WPF, siga estas etapas:

  1. Crie um Novo Projeto WPF: Abra o Visual Studio e crie um novo projeto do tipo "Aplicativo WPF (.NET Framework)" ou "Aplicativo WPF" (.NET Core/.NET 5+).
  2. Instale o Pacote NuGet CefSharp.Wpf:
    • No Gerenciador de Soluções, clique com o botão direito do mouse no seu projeto e selecione "Gerenciar Pacotes NuGet...".
    • Na aba "Procurar", digite "CefSharp" e instale o pacote CefSharp.Wpf. Este pacote trará automaticamente as dependências necessárias, como CefSharp.Common e CefSharp.Core.Runtime.
  3. Ajuste a Plataforma de Compilação: O CefSharp não oferece suporte ao destino de CPU "AnyCPU". É imperativo que você configure seu projeto para compilar como x86 ou x64.
    • No Visual Studio, vá em "Compilar" > "Gerenciador de Configurações...".
    • Na coluna "Plataforma" para o seu projeto, selecione "Nova..." e adicione "x64" ou "x86". Certifique-se de que todas as suas configurações (Debug, Releasee) apontem para a plataforma escolhida.
    • Após fazer a alteração, é recomendável reiniciar o Visual Studio para garantir que todas as ferramentas e referências sejam carregadas corretamente com a nova configuração.

Integração Básica via XAML

A forma mais simples de adicionar um navegador Chromium à sua aplicação WPF é declará-lo diretamente no XAML. Para isso, você precisa adicionar os namespaces CefSharp ao seu arquivo XAML.

Exemplo de XAML (MainView.xaml)

<Window x:Class="MyWpfApp.MainView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:cef_wpf="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf"
        mc:Ignorable="d"
        Title="Visualizador Web Simples" Height="768" Width="1024">
    <Grid>
        <cef_wpf:ChromiumWebBrowser x:Name="WebDisplay" Address="https://www.google.com"/>
    </Grid>
</Window>

Observe a declaração xmlns:cef_wpf="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf", que mapeia o prefixo cef_wpf para os controles CefSharp. O controle ChromiumWebBrowser é então usado diretamente, com a propriedade Address definindo a URL inicial.

Controle Programático e Inicialização Detalhada

Para um controle mais granular sobre o navegador ou para realizra inicializações mais complexas, você pode instanciar e gerenciar o ChromiumWebBrowser programaticamente no código C#.

Exemplo de XAML (MainWindow.xaml) com Grid para Hospedagem

Prmieiro, prepare seu XAML para ter um contêiner (como um Grid) onde o navegador será adicionado dinamicamente.

<Window x:Class="WpfBrowserHost.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="Aplicativo WPF com Browser Incorporado" Height="700" Width="1000" Loaded="OnWindowLoaded">
    <Grid x:Name="MainBrowserContainer">
        <!-- O navegador será adicionado aqui dinamicamente -->
    </Grid>
</Window>

Exemplo de Código C# (MainWindow.xaml.cs)

using CefSharp;
using CefSharp.Wpf;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input; // Necessário para TextCompositionEventArgs

namespace WpfBrowserHost
{
    public partial class MainWindow : Window
    {
        private ChromiumWebBrowser _integratedBrowser;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void OnWindowLoaded(object sender, RoutedEventArgs e)
        {
            SetupChromiumBrowser();
        }

        private void SetupChromiumBrowser()
        {
            // Configurações globais do CefSharp. Deve ser inicializado apenas uma vez.
            var browserConfig = new CefSettings
            {
                // Exemplo: Define o caminho para o cache do navegador
                CachePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "WpfBrowserApp", "Cache"),
                // Exemplo: Habilita depuração remota (pode ser acessada via chrome://inspect)
                // RemoteDebuggingPort = 8088
            };

            if (!Cef.IsInitialized)
            {
                Cef.Initialize(browserConfig);
            }

            // Cria uma nova instância do navegador Chromium
            _integratedBrowser = new ChromiumWebBrowser();
            _integratedBrowser.Address = "https://www.wikipedia.org/wiki/WPF"; // Define a URL inicial

            // Opcional: Anexa um manipulador para eventos de entrada de texto.
            // Isso pode ser útil para corrigir problemas com IME (Input Method Editor)
            // em certos idiomas ou cenários de entrada complexos.
            // _integratedBrowser.PreviewTextInput += HandleBrowserTextInput;

            // Adiciona o navegador ao contêiner Grid definido no XAML
            MainBrowserContainer.Children.Add(_integratedBrowser);
        }

        /// <summary>
        /// Exemplo de manipulador para eventos de entrada de texto.
        /// Pode ser usado para enviar eventos de teclado diretamente ao Chromium para caracteres especiais.
        /// </summary>
        private void HandleBrowserTextInput(object sender, TextCompositionEventArgs e)
        {
            // Esta é uma solução alternativa e pode não ser necessária em todas as versões do CefSharp
            // ou para todos os idiomas. Consulte a documentação do CefSharp para as melhores práticas.
            foreach (char character in e.Text)
            {
                // Exemplo: Envia caracteres "amplos" (fora do ASCII padrão) diretamente.
                // A lógica real para IME seria mais sofisticada.
                if ((int)character > 127) // Caracteres não-ASCII
                {
                    _integratedBrowser.GetBrowser()?.GetHost()?.SendKeyEvent(new CefKeyEvent
                    {
                        Type = KeyEventType.Char,
                        Character = character
                    });
                }
            }
            // e.Handled = true; // Descomente se a manipulação personalizada deve impedir o processamento padrão
        }

        protected override void OnClosed(EventArgs e)
        {
            // Importante: Libera recursos do CefSharp ao fechar a janela.
            // Isso deve ser feito APENAS uma vez no ciclo de vida da aplicação,
            // geralmente ao fechar a janela principal.
            _integratedBrowser?.Dispose(); // Libera o controle do navegador
            Cef.Shutdown(); // Desliga o motor Chromium
            base.OnClosed(e);
        }
    }
}

Gerenciando a Navegação e Pop-ups (ILifeSpanHandler)

Por padrão, quando um link é clicado para abrir em uma nova janela ou aba (por exemplo, target="_blank"), o CefSharp tentará criar uma nova instância do navegador, o que pode não ser o comportamento desejado para uma aplicação desktop integrada. Para controlar esse comportamento e forçar todos os links a abrirem na mesma instância do navegador, você pode implementar a interface ILifeSpanHandler.

Criação de um Manipulador de Ciclo de Vida do Navegador

Crie um novo arquivo de classe (por exemplo, BrowserLifecycleHandler.cs) e adicione o seguinte código:

using CefSharp;
using CefSharp.Wpf;

namespace WpfBrowserHost
{
    /// <summary>
    /// Implementação de ILifeSpanHandler que impede a criação de novos pop-ups
    /// e redireciona a URL para a instância atual do navegador.
    /// </summary>
    public class BrowserLifecycleHandler : ILifeSpanHandler
    {
        public bool DoClose(IWebBrowser webBrowser, IBrowser browser)
        {
            // Retorna 'false' para permitir que o navegador feche normalmente.
            // Retorne 'true' para impedir o fechamento (útil para janelas principais).
            return false;
        }

        public void OnAfterCreated(IWebBrowser webBrowser, IBrowser browser)
        {
            // Este método é chamado após a criação de uma nova janela do navegador.
            // Para o objetivo de redirecionar pop-ups, nenhuma ação específica é necessária aqui.
        }

        public void OnBeforeClose(IWebBrowser webBrowser, IBrowser browser)
        {
            // Este método é chamado antes do fechamento de uma janela do navegador.
        }

        public bool OnBeforePopup(IWebBrowser webBrowser, IBrowser browser, IFrame frame, string targetUrl,
                                  string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture,
                                  IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings,
                                  ref bool noJavascriptAccess, out IWebBrowser newBrowser)
        {
            // Quando um pop-up está prestes a ser criado, este método é invocado.
            // Definimos 'newBrowser' como null para indicar que não queremos uma nova instância de navegador.
            newBrowser = null;

            // Tentamos converter o controle genérico IWebBrowser para o tipo específico ChromiumWebBrowser do WPF.
            var wpfBrowserControl = webBrowser as ChromiumWebBrowser;
            if (wpfBrowserControl != null)
            {
                // Carregamos a 'targetUrl' (a URL do pop-up) na instância atual do navegador.
                wpfBrowserControl.Load(targetUrl);
            }

            // Retornar 'true' cancela a criação do pop-up original.
            // Se você retornasse 'false', o CefSharp tentaria criar uma nova janela/pop-up.
            return true;
        }
    }
}

Aplicando o Manipulador de Ciclo de Vida

Para que o manipulador funcione, você deve atribuir uma instância de BrowserLifecycleHandler à propriedade LifeSpanHandler do seu ChromiumWebBrowser. Adicione a seguinte linha no método SetupChromiumBrowser (ou onde você inicializa _integratedBrowser):

// ... dentro do método SetupChromiumBrowser()
_integratedBrowser = new ChromiumWebBrowser();
_integratedBrowser.Address = "https://www.wikipedia.org/wiki/WPF";

// Atribui o manipulador de ciclo de vida personalizado
_integratedBrowser.LifeSpanHandler = new BrowserLifecycleHandler();

// ... restante do código para adicionar ao Grid

Tags: CefSharp WPF C# ChromiumWebBrowser .NET

Publicado em 7-27 11:56