Cómo usar CefSharp (chromium framework embebido C#) en una aplicación Winforms

Cómo usar CefSharp (chromium framework embebido C#) en una aplicación Winforms

CefSharp es la manera más facil de incluir un explorador con todas las funciones estándares (sin depender de la versión de Internet Explorer del usuario) en tu aplicación de Winforms en C# or VB.NET. CefSharp te permite agregar controles web en tus aplicaciones de Winforms y WPF, además de una version headless (sin interfaz) para la automatización de proyectos. CefSharp está basado en Chromium Embedded Framework, la version open source de Google Chrome. Puedes obtener más información acerca del proyecto CefSharp en la página oficial aquí.

Puedes usar CefSharp como un componente de Explorador (explorador web) para no depender, como mencionamos anteriormente, de la versión de internet explorer del usuario ó como una interfaz de usuario predeterminada para tu aplicación. Sí, puedes usar controles HTML (botones, cajas de texto) en tu aplicación de C# y personalizarla con CSS como quieras (Bootstrap etc.).

Esta es tu oportunidad para crear agradables aplicaciones nativas para Windows usando HTML, Javascript y CSS así que comencemos. En este artículo trabajaremos con la versión 49.0 de CefSharp.

Requisitos

  • Necesitarás Visual Studio con el manager de paquetes NuGet (NuGet Package Manager) es decir, Visual Studio 2010 o mayor.

1. Crea una aplicación de Winform y añade CefSharp usando NuGet

Procede a crear una aplicación de Winforms como lo haces siempre usando la ultima versión de .NET Framework. Nada dificil, verdad? Ahora antes de proceder con CefSharp verifica que tu computadora tenga las siguientes redistribuciones instaladas:

Así que procura instalarlos antes de continuar, de otra manera encontrarás errores como:

Ahora despues de la creación del proyecto, agrega CefSharp. Para agregar CefSharp, ve al explorador de soluciones (Solution Explorer) en la parte superior derecha de Visual Studio, luego haz click derecho en tu aplicación (Bajo la aplicación) y selecciona Administrar NuGet Packages (Manage NuGet Packages).

CefSharp nugget package manager

Cuando el menú de busqueda aparezca, escribe "cefsharp", selecciona la distribución de WinForms y procede a instalar.

When the search menu appears, type cefsharp , select the WinForms distributtion and install it.

Como en cada versión de Visual Studio, la interfaz puede variar, solo debes estar seguro de instalar la distribución de CefSharp.WinForms por The CefSharp localizado en nuget.org. En este ejemplo estamos usando Visual Studio 2015.

CefSharp NuGet package

Sigue el proceso de instalación (acepta los terminos y continua con la instalación). Durante la instalación deberías ver información relacionada al proceso de instalación en la consola.

2. Cambia la configuración de plataforma (x86 or x64)

Despues de instalado, procede a instalar la configuración de tu proyecto con el administrador de configuración.

CefSharp do not build anyCPU

Como boromir dice, la plataforma de destino de tu proyecto no puede ser anyCPU, este debe ser de x86 or x64 de otra maner obtendrás la siguiente advertencia en tu consola y la aplicación no compilara:

Procede a cambiarla en el Administrador de configuración. Haz click derecho en el explorador de soluciones en la parte superior derecha de Visual Studio (directamente en la solución) y selecciona el Administrador de configuración (Configuration Manager):

CefSharp configuration manager

Y selecciona la plataforma que coincide con los requisitos de tu proyecto:

Correct platform cefsharp

Cabe destacar que necesitarás crear las plataformar x86 or x64 en caso de que no existan seleccionando la opción <Nuevo...>.

Despues de configurar los requisitos basicos de CefSharp en tu proyecto, este podrá compilar satisfactoriamente pues tenemos todo lo que se necesita para ejecutar Chromium. Ahora simplemente necesitamos agregar el control a un formulario y aprender a manipularlo con código.

3.1. Usando CEF (como explorador web)

Ahora que nuestra aplicación tiene CefSharp integrado, necesitamos manipularlo con código. Primero que todo, importa CefSharp en el formulario agregando los siguientes estamentos using en la cabecera de tu clase:

using CefSharp;
using CefSharp.WinForms;

Ahora agrega el siguiente método en tu clase y crea una variable accessible localmente en esa clase (para que pueda ser accesible por los otros métodos):

public ChromiumWebBrowser chromeBrowser;

public void InitializeChromium()
{
   CefSettings settings = new CefSettings();
   // Inicializar CEF con la configuración proporcionada
   Cef.Initialize(settings);
   // Crear un componente de explorador web chromium
   chromeBrowser = new ChromiumWebBrowser("http://ourcodeworld.com");
   // Agregar componente al formulario y cubrir todo el formulario con el
   this.Controls.Add(chromeBrowser);
   chromeBrowser.Dock = DockStyle.Fill;
}

Este método inicializará CefSharp en el proyecto y agregará el control en el formulario (el formulario completo será un explorador, puedes limitar el tamaño del control si lo deseas). Ahora debes ejecutarlo despues de la función InitializeComponent() de tu clase (que normalmente está en el constructor):

public Form1()
{
     InitializeComponent();
     // Iniciar el explorador despues de cargar los otros componentes
     InitializeChromium();
}

Tampoco olvides cerrar el componente cef en el evento FormClosing de tu formulario:

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
     Cef.Shutdown();
}

Finalmente esto debería bastar para la ejecución de CefSharp como un explorador básico en tu aplicación. La clase completa debería lucir similar a (teniendo en cuenta que el proyecto creado se llama embebbedChromium):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using CefSharp;
using CefSharp.WinForms;

namespace embebbedChromium
{
    public partial class Form1 : Form
    {
        public ChromiumWebBrowser chromeBrowser;
 
        public Form1()
        {
            InitializeComponent();
            // Iniciar explorador despues de los componentes
            InitializeChromium();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            
        }

        public void InitializeChromium()
        {
            CefSettings settings = new CefSettings();
            Cef.Initialize(settings);
            chromeBrowser = new ChromiumWebBrowser("http://ourcodeworld.com");
            this.Controls.Add(chromeBrowser);
            chromeBrowser.Dock = DockStyle.Fill;
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Cef.Shutdown();
        }        
    }
}

Ahora inicia tu aplicación (F5) o clickea el boton Iniciar en la barra de herramientas y verás cómo Our Code World carga en tu aplicación de Winforms.

Our Code World in CefSharp browser

Felicitaciones! acabas de implementar CefSharp en tu aplicación en su más basica expresión. Te recomendamos leer atentamente la documentación del Framework para ver como puedes crear cosas más asombrosas.

3.2. Usando CEF (como interfaz de usuario)

En el punto anterior, implementaste CefSharp como un componente de explorador. Sin embargo, puedes hacer más que eso, ahora implementaremos una aplicación puramente basada en HTML, Javascript y CSS (Bootstrap) con archivos locales para manipular cosas del sistema.

Necesitamos incluir nuestros recursos HTML en nuestro Proyecto de Visual Studio. Puedes crearlas directamente desde visual studio o el explorador de windows, sin embargo con visual studio es más facil pues la carpeta será añadida automaticamente a los recursos del proyecto.

En este caso vamos a usar una simple interfaz de Bootstrap (que incluye bootstrap y jQuery) basado en la siguiente estructura de carpetas:

Folder path

Despues de agregarlas en tu proyecto de visual studio (click derecho en el explorador de soluciones, agregar carpeta y copiar tus recursos en html-resources), el proyecto debería lucir así:

Visual Studio Resources explorer

Importante: ahora necesitas seleccionar todas las carpetas y archivos de la carpeta y ejecutar las siguiente acciones:

  • Selecciona todos las carpetas html,js,css a archivos dentro de la carpeta.
  • En la parte inferior (tabla de propiedades) selecciona la opcion de Copiar a directorio de salida (Copy to Output Directory) y selecciona la opcion Copiar siempre (Copy Always).

Copy Always

Ahora necesitamos configurar CefSharp para que apunte a nuestro archivo index.html en vez de una URL web. Como nuestra carpeta de recursos está localizada en el proyecto puedes usar el siguiente código para obtener el directorio de los recursos:

// En vez de usar una url web como http://ourcodeworld.com , declararemos la variable "page" para que cargue un recurso local
String page = string.Format(@"{0}\html-resources\html\index.html", Application.StartupPath);

Cabe destacar que necesitas proporcionar una dirección completa de tu archivo local siempre (c:/carpeta/archivo.html). Como un proyecto normal debería funcionar en cualquier directorio, el StartupPath nos propocionara la carpeta en la que nos encontramos.

Sin embargo, esto no funcionar todavia pues si intentas ejecutar, obtendrás un pantallazo blanco. Primero necesitas:

  1. Exponer una clase de C# para ser usada desde Javascript como un Objeto.
  2. Permitir el uso de archivo locales (file://).

Vamos a exponer una clase de C# en Javascript para manipular caracteristicas nativas con funciones de Javascript. Necesitas crear primero una clase, esta esperará 2 argumentos en el constructor (ChromiumBrowserInstance y el Formulario donde se encuentra el Componente de CefSharp). Esta clase tendrá 2 funciones, una que iniciará la consola de desarrollador de Chromium y la otra que iniciará la consola de comandos de Windows (cmd.exe).

La clase debería lucir similar a:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using CefSharp;
using CefSharp.WinForms;
using System.Diagnostics;

namespace embebbedChromium
{
    class CefCustomObject
    {
        // Declara una variable local de Chromium y del formulario para ejecutar acciones sobre ellas en el thread principal
        private static ChromiumWebBrowser _instanceBrowser = null;
        // La clase del formulario necesita cambiar de acuerdo al nombre de la tuya
        private static Form1 _instanceMainForm = null;


        public CefCustomObject(ChromiumWebBrowser originalBrowser, Form1 mainForm)
        {
            _instanceBrowser = originalBrowser;
            _instanceMainForm = mainForm;
        }

        public void showDevTools()
        {
            _instanceBrowser.ShowDevTools();
        }

        public void opencmd()
        {
            ProcessStartInfo start = new ProcessStartInfo("cmd.exe", "/c pause");
            Process.Start(start);
        }
    }
}

La clase será expuesta en Javascript luego pues como puedes ver, es muy sencilla: muestra la consola de desarrollador e iniciar el proceso cmd.exe.

Ahora nuestra funcion de InitializeChromium lucirá así:

public void InitializeChromium()
{
    CefSettings settings = new CefSettings();
    // Cabe destacar que si obtienes un error o una pantalla blanca, puedes estar haciendo algo mal!
    // Intenta cargar un archivo local para estar seguro de que existe y provee la dirección completa para probar
    // Por ejemplo, remplaza la pagina con un directorio completo:
    // String page = @"C:\Users\SDkCarlos\Desktop\una-carpeta\index.html";

    String page = string.Format(@"{0}\html-resources\html\index.html", Application.StartupPath);
    //String page = @"C:\Users\SDkCarlos\Desktop\artyom-HOMEPAGE\index.html";

    if (!File.Exists(page))
    {
        MessageBox.Show("Error el archivo HTML no existe: "+page);
    }
    
    // Inicializar CEF con la configuración proporcionada
    Cef.Initialize(settings);
    // Crea un componente de Explorador Web
    chromeBrowser = new ChromiumWebBrowser(page);
       
    // Agregar el control al formulario y que llene el formulario completo
    this.Controls.Add(chromeBrowser);
    chromeBrowser.Dock = DockStyle.Fill;
    
    // Permitir el uso de recursos locales desde el explorador.
    BrowserSettings browserSettings = new BrowserSettings();
    browserSettings.FileAccessFromFileUrls = CefState.Enabled;
    browserSettings.UniversalAccessFromFileUrls = CefState.Enabled;
    chromeBrowser.BrowserSettings = browserSettings;
}

Usamos el método File.Exists para verificar que la dirección proporcionada existe, de otra manera hiciste algo mal en alguno de los pasos anteriores.

Ahora solamente debemos exponer nuestra clase en la función de InitializeComponent y ejecutarla:

public Form1()
{
    InitializeComponent();
    // Inicia el explorador Chromium
    InitializeChromium();
    // Registrar un Objeto global en Javascript llamado "cefCustomObject" con las funciones de la clase CefCustomObject creada previamente :3
    chromeBrowser.RegisterJsObject("cefCustomObject", new CefCustomObject(chromeBrowser, this));
}
  • Se cuidadoso si tu proyecto se localiza en una particion distinta a la que se encuentra windows mientras programas (C://) pues otros directorios tienden a no funcionar.
  • Cabe destacar que la función RegisterJsObject registra un objeto global con las funciones de la clase expuesta con el nombre proporcionado en el primer argumento.  En este caso la variable global en Javascript será cefCustomObject.

Eso es todo! Ahora debes probar tu aplicación, la clase principal debería lucir similar a (con todo el código agregado):

using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using CefSharp;
using CefSharp.WinForms;
using System.Runtime.InteropServices;

namespace embebbedChromium
{
    public partial class Form1 : Form
    {
        public ChromiumWebBrowser chromeBrowser;

        public Form1()
        {
            InitializeComponent();
            InitializeChromium();
            chromeBrowser.RegisterJsObject("cefCustomObject", new CefCustomObject(chromeBrowser, this));
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            chromeBrowser.ShowDevTools();
        }

        public void InitializeChromium()
        {
            CefSettings settings = new CefSettings();

            String page = string.Format(@"{0}\html-resources\html\index.html", Application.StartupPath);
            //String page = @"C:\Users\SDkCarlos\Desktop\artyom-HOMEPAGE\index.html";

            if (!File.Exists(page))
            {
                MessageBox.Show("Error el archivo HTML no existe : "+page);
            }
            
            Cef.Initialize(settings);
            chromeBrowser = new ChromiumWebBrowser(page);
               
            this.Controls.Add(chromeBrowser);
            chromeBrowser.Dock = DockStyle.Fill;
            
            BrowserSettings browserSettings = new BrowserSettings();
            browserSettings.FileAccessFromFileUrls = CefState.Enabled;
            browserSettings.UniversalAccessFromFileUrls = CefState.Enabled;
            chromeBrowser.BrowserSettings = browserSettings;
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Cef.Shutdown();
        }
    }
}

Por el lado de Javascript, como dijimos anteriormente la función RegisterJsObject crea un objeto con el nombre proporcionado en el primer argumento. En el archivo index.html vamos a agregar los siguiente botones que ejecutan las funciones expuestas en la clase de C#:

<button class="btn btn-info" onclick="cefCustomObject.showDevTools();">Open Chrome Dev Tools</button>
<button class="btn btn-primary" onclick="cefCustomObject.opencmd();">Open cmd.exe</button>

Recuerda respetar el "camelCase", el método en C# necesita iniciar con minuscula y obedecer la regla de camelCase (mayusculas y minusculas sin usar guion bajo _ o guion -)" como mostrado anteriormente.

Como puedes ver, con CefSharp todo es bi-direccional, puedes manipular Javascript desde C# or manipular C# desde Javascript dinamica y facilmente.

Ahora inicia tu aplicación y disfruta de controles HTML como interfaz grafica para el usuario en Windows!

Chrome final HTML UI

Si haces debug en la clase registrada en Javascript, verás un objeto con los mismos metodos y funciones en el código nativo (equals, getHashCode and toString son automaticamente agregados).

Javascript Object registered with C#

Que te diviertas !

Esto podría ser de tu interes

Conviertete en un programador más sociable