CefSharp是Chromium的.NET版封装,用于在WinForm和WPF中嵌入浏览器功能,并能让C#代码和页面进行交互。

CEF是Chromium Embedded Framework的简称,这个框架专门用于将Chromium嵌入到其他程序中。而CefSharp在这个框架的基础上封装了.NET版,Github开源:https://github.com/cefsharp/CefSharp

CefSharp支持WinForm和WPF,本文讲解一下在WinForm中C#和页面的交互,官方Wiki有文档,可以加深了解。

首先创建一个WinForm项目,安装NuGet包CefSharp.WinForms,注意安装NuGet需要很长时间,所有依赖大概400M。

在程序启动时需要初始化Cef一次,所以在Program.cs中添加以下代码。

static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    var setting = new CefSharp.CefSettings();
    setting.Locale = "zh-CN";
    setting.CachePath = "cache";
    CefSharp.Cef.Initialize(setting);

    Application.Run(mainForm = new Form1());

    CefSharp.Cef.Shutdown();
}

即必须调用Cef.Initialize()初始化才能使用,程序退出时必须Shutdown,Cef.Shutdown()方法可以调用多次,务必保证被调用,否则运行几次内存就爆了。

下面来看具体实现代码,后边详细讲解。

using System;
using System.Windows.Forms;
using CefSharp;
using CefSharp.WinForms;

namespace cef
{
    public partial class Form1 : Form
    {
        private ChromiumWebBrowser browser;

        public Form1()
        {
            InitializeComponent();

            //初始化控件并添加到Form
            browser = new ChromiumWebBrowser("http://www.abelliu.com");

            browser.Dock = DockStyle.Fill;
            this.panelBottom.Controls.Add(browser);

            browser.FrameLoadEnd += Browser_FrameLoadEnd;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //注册C#的方法到页面中
            var obj = new BoundObject();
            browser.RegisterJsObject("bound", obj);
        }

        //页面加载完注入我们的JS代码
        private void Browser_FrameLoadEnd(object sender, CefSharp.FrameLoadEndEventArgs e)
        {
            if (e.Frame.IsMain)
            {
                browser.ExecuteScriptAsync(@"
                document.body.onmouseup = function() {
                    bound.onSelected(window.getSelection().toString());
                }");
            }
        }

        public void ShowJsResult(string message)
        {
            this.Invoke(new Action(() => { this.richTextBox1.Text = message; }));
        }

    }

    public class BoundObject
    {
        public void OnSelected(string selectedText)
        {
            Program.mainForm.ShowJsResult(selectedText);
        }
    }

}

我们定义了一个类BoundObject和一个方法OnSelected()来实现在JS中调用,类和方法名随意,但是特别注意,方法参数必须用首字母小写的驼峰命名

Form1_Load中使用browser.RegisterJsObject("bound", obj);将我们的类封装并在页面的JS引擎中注册,然后Browser_FrameLoadEnd事件中注入我们需要执行的JS,JS中调用bound.onSelected()就会调到我们的C#代码。这个bound名随意。注意在JS调用时的名称都是标准的驼峰名字,首字母小写,因为这是JS的标准命名方法,我也是因为调用不成功测试了好久才发现。。

现在运行程序,使用鼠标选择页面中的文字,然后选择的文字会展示在WinForm中。

本文源码在GitHub:https://github.com/Abel-Liu/CefSharpSample