WebView2 no WinForms: UI em HTML dentro de app desktop
WebView2 WinForms é a combinação que uso no WS-engine pra ter um painel desktop com cara moderna sem me enfiar numa curva íngreme de WPF. É um controle oficial da Microsoft que embute um Chromium dentro de um Form clássico — o resultado é que a interface da aplicação é HTML, CSS e JavaScript locais,

WebView2 WinForms é a combinação que uso no WS-engine pra ter um painel desktop com cara moderna sem me enfiar numa curva íngreme de WPF. É um controle oficial da Microsoft que embute um Chromium dentro de um Form clássico — o resultado é que a interface da aplicação é HTML, CSS e JavaScript locais, e o backend em C# conversa com o painel por mensagens JSON. Este artigo mostra o código real dessa integração, decisões de arquitetura e os cuidados que descobri na prática. Pra contexto maior, o guia de engenharia reversa com IA.
Por que WebView2 e não WPF puro
Primeira tentativa foi WPF nativo. Travei na segunda tela — DataGrid com estilo decente exige conhecimento específico, animações precisam de storyboard, binding de dados tem armadilhas sutis com threads. Boa escolha pra quem já domina a stack, mas eu não dominava. Horas de leitura pra fazer uma barra de progresso ter transição suave que, em CSS, seriam duas linhas.
WebView2 WinForms resolve o problema trocando a curva. Em vez de aprender WPF do zero, reaproveito conhecimento web que já tenho — flexbox, grid, variáveis CSS, event listeners em JS. O custo é embarcar o runtime do Chromium, mas no Windows 10 recente e no Windows 11 ele já vem instalado como componente do sistema. Pra projeto pessoal com UI que precisa iterar rápido, foi a decisão certa.
Instalar o controle via NuGet Microsoft.Web.WebView2
O controle vem do pacote NuGet Microsoft.Web.WebView2. Adicionei via Visual Studio, mas também funciona por linha de comando com nuget install. O pacote traz dois namespaces principais: Microsoft.Web.WebView2.Core (contratos e eventos de baixo nível) e Microsoft.Web.WebView2.WinForms (o controle visual).
Além do pacote, o usuário final precisa do Edge WebView2 Runtime instalado no sistema. No Windows 11 e no Windows 10 recente ele vem junto; em instalações mais antigas, pode faltar. O código precisa prever isso graciosamente — captura exceção específica e orienta o usuário a instalar.
Hospedar o controle no WinForms com Dock Fill
Dentro do Form principal, instancio o controle com new WebView2 { Dock = DockStyle.Fill } e adiciono como filho de um painel. Dock Fill garante que o WebView ocupa todo o espaço disponível do container e redimensiona junto com a janela. Pra separar o painel HTML de controles clássicos do Form (barra de menu, status bar), uso um Panel container e deixo o Dock do WebView dentro dele.
Essa separação importa quando quero misturar controles nativos com HTML. Por exemplo, menu principal em WinForms (ganha de graça o estilo nativo do Windows) e corpo em WebView2 (ganha a estética custom). O controle do WebView2 WinForms coexiste com qualquer outro controle do Form sem fricção.
EnsureCoreWebView2Async e tratar runtime ausente
Inicializar o controle não é síncrono. Precisa chamar EnsureCoreWebView2Async(null) e aguardar — essa chamada baixa configuração do runtime, prepara o ambiente de execução e emite erros se faltar algo. O argumento null usa o environment padrão (adequado pra 99% dos casos).
Importante: a chamada pode lançar WebView2RuntimeNotFoundException quando o runtime não está instalado. No WS-engine, capturo essa exceção específica e mostro um MessageBox com link direto pra página de download do runtime. Sem esse tratamento, o app abre, tenta inicializar e falha silenciosamente — usuário leigo não entende por que a janela ficou em branco.
Carregar HTML local via URI absoluta file://
O painel não é servido por servidor HTTP local. É um arquivo index.html no disco, dentro da pasta assets/webview/ do executável. Pra navegar pra ele, construo uma URI absoluta no formato file:// e chamo CoreWebView2.Navigate(new Uri(_htmlPath).AbsoluteUri). O new Uri(path).AbsoluteUri cuida da codificação (espaços, caracteres especiais) sem eu precisar lembrar das regras.
Esse padrão de servir HTML do disco local tem vantagem clara pra apps desktop: zero latência, zero dependência de rede, zero porta de servidor a configurar. O JS do painel pode fazer fetch pra APIs externas se precisar, mas o esqueleto da interface é um arquivo estático lido do disco. Mantenho os assets em index.html + app.js + style.css, três arquivos sem build step — editei direto, recarreguei a janela, vi o resultado.
IPC: PostWebMessageAsJson (C#→JS) e WebMessageReceived (JS→C#)
A ponte entre o backend em C# e o JS do painel funciona por mensagens JSON em ambas as direções. Do C# pro JS, chamo _webView.CoreWebView2.PostWebMessageAsJson(json). Do JS pro C#, uso window.chrome.webview.postMessage(obj) e, no C#, assino CoreWebView2.WebMessageReceived.
No WS-engine, defini duas shapes de mensagem. Backend pro UI usa { type: "leaderboard"|"timer"|"status"|"capture", ... payload }. UI pro backend usa { cmd: "toggle"|"reset"|"save"|"filter"|"ready", args: {...} }. O "ready" é o primeiro — o JS avisa o backend quando terminou de carregar e está pronto pra receber dados. Até esse ping chegar, o backend não começa a empurrar snapshots.
Parser JSON do lado do C# pode ser qualquer coisa — Newtonsoft.Json, System.Text.Json. Pra evitar dependência adicional no projeto do WebView2 WinForms, usei Regex simples pra extrair os campos que me interessavam. Vale pra mensagens pequenas e previsíveis; projetos maiores usariam um parser real sem pensar duas vezes.
Vantagens práticas: iterar sem recompilar o .exe
O ganho que mais me surpreendeu: iterar o painel sem recompilar o executável. Como os arquivos HTML/CSS/JS são lidos do disco a cada carga, posso editar app.js ou style.css no editor, fechar e reabrir a janela principal, e ver o novo visual — sem passar pelo compilador C#. Em sessões de ajuste visual, isso acelera muito.
Pra uso em produção, embarquei os arquivos na pasta do executável e eles seguem como assets normais na distribuição. O usuário final não vê diferença entre interface compilada e interface servida por disco; o que ele vê é um painel que abre junto com o programa. Dentro da pasta de distribuição, uma subpasta assets/webview guarda o index.html, o app.js, o style.css e qualquer ícone usado no painel. Zero build step, zero bundle, zero minificação — se o painel ficar grande demais, dá pra adicionar um step de build depois sem mudar o fluxo de carregamento no C#.
O conjunto WebView2 WinForms + HTML local é o atalho mais pragmático que achei pra desktop no Windows com cara moderna. Troca a complexidade de WPF pela complexidade de embarcar um Chromium que o Windows atual já tem instalado — pra mim, troca válida e repetível em outros projetos pequenos. Pra ver essa combinação em um projeto completo, dá uma volta no ModoDev.
Avalie este artigo
Continue lendo
Inteligência ArtificialMapear protocolo binário desconhecido com ajuda da IA
Encarar um protocolo binário desconhecido é um exercício específico de paciência: você tem bytes brutos, nenhum manual, e precisa transformar isso em código…
Inteligência ArtificialCapturar e analisar pacotes com Wireshark: guia GUI
analisar pacotes Wireshark é o primeiro passo em qualquer projeto que precise entender o que uma aplicação está mandando pela rede. No WS-engine, foi a…
Inteligência ArtificialEngenharia reversa com IA: construí um meter de MMORPG
Comecei o WS-engine sem nenhuma experiência prévia em engenharia reversa com IA . Em quatro meses saí do zero a um meter de dano funcional para um MMORPG, com…
Comentários
Carregando comentários...