手把手教你使用CefSharp开发Winform(Winform中使用浏览器处理html页面)

 

第一步:了解什么是CefSharp

CefSharp简单来说就是一款.Net编写的浏览器包,方便你在Winform和WPF中内嵌的Chrome浏览器组件,用过Chrome内核组件来加载处理html页面,以此实现你在winform中访问网页或处理html页面。

为什么要使用CefSharp?个人觉得有以下方面好处:

1)当你无法用winform控件来实现一些界面样式或者html才能实现的一些功能的时候,你就需要将你的winform界面改为html+js来处理,比如:echart丰富的报表,高大上的智慧中心大屏;

2)当你开发的是B/S架构的在线应用,但是在使用过程中又需要访问本地电脑的硬件的时候,普通的浏览器无法达到效果,就通过C#来处理与硬件的交互,并把处理方法暴露给前端html来通过JS调用,比如:调用读卡器,扫描仪,摄像头等;

3)你自己发挥想象,比如需要编写winform窗体与html页面混合的应用程序,并且需要进行交互的时候。

GitHub地址:传送门
wiki帮助文档地址:传送门
CefSharp最小的示例工程:传送门
gitter交流讨论区:传送门

第二步:准备搭建环境及工具

1)所需环境及工具:

① Visual Studio(个人建议2015及以上)

② CefSharp.WinForms及其依赖的包(我使用的最新版是84.0.0):

CefSharp.WinForms Nuget包  

CefSharp.Common Nuget包

cef.redist.x64 Nuget包

③ .Net Framework4.5.2
 

2)创建Winform项目;

在VS中新建一个“Windows窗体应用程序”(Winform工程)。

3)引用CefSharp

网上有很多教程是教你如何将CefSharp.WinForms及其依赖包下载的本地再添加引用。其实没必要,nuget网速也不至于这么差。

直接在项目中通过程序包管理器的NuGet 命令来添加引用就行。

在程序包管理器控制台输入以下命令安装CefSharp.WinForms:

Install-Package CefSharp.WinForms

在程序包管理器控制台输入以下命令安装CefSharp.Common:

Install-Package CefSharp.Common

在安装CefSharp.Common的时候,nuget会自动安装cef.redist.x64和cef.redist.x86.所以真的不需要像其他文章说的那样,一个个下载下来手动安装;

4)修改.net 目标框架为4.5.2以上或以上版本

 

5)配置管理器选择目标平台

CefSharp在Any CPU平台下无法正常运行。所以要修改配置。选中解决方案名称右键,进入解决方案属性页。找到配置属性,然后将目标平台改为x86或者x64。;


 

第三步:开始搭建一个Winform浏览器

form窗体中添加一个变量;

然后在Form1方法中编写以下代码(注意,以下代码只能在Form窗体方法中添加,不能写在Form_Load方法中;

// Start the browser after initialize global component
CefSettings settings = new CefSettings();

string page = "http://baidu.com";

// Initialize cef with the provided settings
Cef.Initialize(settings);
// Create a browser component
chromeBrowser = new ChromiumWebBrowser(page);

// Add it to the form and fill it to the form window.
this.Controls.Add(chromeBrowser);
chromeBrowser.Dock = DockStyle.Fill;

// Allow the use of local resources in the browser
BrowserSettings browserSettings = new BrowserSettings();
browserSettings.FileAccessFromFileUrls = CefState.Enabled;
browserSettings.UniversalAccessFromFileUrls = CefState.Enabled;
chromeBrowser.BrowserSettings = browserSettings;

然后运行就可以看到效果;

除了访问web在线网页以外,还可访问本地的html页面。只需要将网页链接地址替换为本地html页面地址(绝对路径),第四步会有讲到如何访问本地html页面;

 

第四步:使用JS调用C#方法进行交互

如果要访问本地的html页面,则可以将html页面文件放置在程序根目录,这样方便程序拷贝到任何地方,只要同路径都可以访问;

1)首先,我们将需要访问的html以及css样式文件,js脚本文件等拷贝到程序根目录下。

2)然后修改之前我们编写的代码。新建一个方法名InitializeChromium()。将我们之前写好的代码放入里面。并将访问页面改为本地html地址;

/// <summary>
/// 初始化浏览器并启动
/// </summary>
public void InitializeChromium()
{
    CefSettings settings = new CefSettings();
    // 获取本地html路径地址
    String page = string.Format(@"{0}\ViewData\html\Index.html", Application.StartupPath);

    if (!File.Exists(page))
    {
        MessageBox.Show("Error The html file doesn't exists : " + page);
    }
           
    // Initialize cef with the provided settings
    Cef.Initialize(settings);
    // Create a browser component
    chromeBrowser = new ChromiumWebBrowser(page);

    // Add it to the form and fill it to the form window.
    this.Controls.Add(chromeBrowser);
    chromeBrowser.Dock = DockStyle.Fill;

    // Allow the use of local resources in the browser
    BrowserSettings browserSettings = new BrowserSettings();
    browserSettings.FileAccessFromFileUrls = CefState.Enabled;
    browserSettings.UniversalAccessFromFileUrls = CefState.Enabled;
    chromeBrowser.BrowserSettings = browserSettings;

}

 3)然后再Form1方法中调用InitializeChromium();

4)接下来我们编写与前端JS交互的方法;

   新建一个类,我取名为CefCustomObject。然后编写初始化类的代码和需要被调用方法的代码;

 public class CefCustomObject
    {
        // Declare a local instance of chromium and the main form in order to execute things from here in the main thread
        private static ChromiumWebBrowser _instanceBrowser = null;
        // The form class needs to be changed according to yours
        private static Form1 _instanceMainForm = null;
       
        public CefCustomObject(ChromiumWebBrowser originalBrowser, Form1 mainForm)
        {
            _instanceBrowser = originalBrowser;
            _instanceMainForm = mainForm;
        }

        /// <summary>
        /// 窗口加载完毕时需要出发的全局JS对象;
        /// </summary>
        public void OnFrameLoadEnd(object sender, FrameLoadEndEventArgs e)
        {
            if (e.Frame.IsMain)
            {
                    _instanceBrowser.ExecuteScriptAsync(@"
              document.body.onmouseup = function()
              {
                bound.onSelected(window.getSelection().toString());
              }
            ");
            }
        }

        /// <summary>
        /// 显示一个弹出对话框,前端JS调用的方法
        /// </summary>
        /// <param name="msg">传入参数</param>
        public void showAlertMsg(string msg)
        {
            MessageBox.Show("The user selected some text [" + msg + "]");
        }
        
        // 自定义被JS调用的方法,读取身份证信息
        public string ReadIdCard()
        {
            // 具体调用读身份证读卡器的方法
            // IDCardModel model=IDCardSdk.Read();
            //将身份证信息返回给前端;
            // return model.ToJson();
            return "调用失败";
        }
    }
}

5)在Form1方法中再添加对暴露给前端JS调用的类进行注册的代码;

 bound为被前端调用方法的顶级函数名。CefCustomObject为需要被注册的类;下面代码的含义,可参照我另一篇文章新版本CefSharp.Winform 实现和js交互(JS调用C#方法)

//需要添加此句代码,否则下面执行会报错
            CefSharpSettings.LegacyJavascriptBindingEnabled = true;
            // 79.0.0以下旧方法注册
            //chromeBrowser.RegisterJsObject("bound", new CefCustomObject(chromeBrowser, this), new CefSharp.BindingOptions { CamelCaseJavascriptNames = false });

            // 79.0.0以上的新方法注册
            CefSharpSettings.LegacyJavascriptBindingEnabled = true;
            CefSharpSettings.WcfEnabled = true;
            chromeBrowser.JavascriptObjectRepository.Register("bound", new CefCustomObject(chromeBrowser, this), isAsync: false, options: BindingOptions.DefaultBinder);

至此,即可运行。html页面中调用bound.showAlertMsg("测试内容")。就会弹出对话框;调用成功。注意(前端调用的方法名必须为首字母小写,否则无后端方法无法被调用)

 

最后完整代码:

后端Form1窗体代码:

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

namespace CefSharpWinformDemo
{
    public partial class Form1 : Form
    {
        public ChromiumWebBrowser chromeBrowser;
        private CefCustomObject WebBrowserHelper;

        public Form1()
        {
            InitializeComponent();

            // Start the browser after initialize global component
            InitializeChromium();

            //需要添加此句代码,否则下面执行会报错
            CefSharpSettings.LegacyJavascriptBindingEnabled = true;
            // 79.0.0以下旧方法注册
            //chromeBrowser.RegisterJsObject("bound", new CefCustomObject(chromeBrowser, this), new CefSharp.BindingOptions { CamelCaseJavascriptNames = false });

            // 79.0.0以上的新方法注册
            CefSharpSettings.LegacyJavascriptBindingEnabled = true;
            CefSharpSettings.WcfEnabled = true;
            chromeBrowser.JavascriptObjectRepository.Register("bound", new CefCustomObject(chromeBrowser, this), isAsync: false, options: BindingOptions.DefaultBinder);
        }

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

        /// <summary>
        /// 初始化浏览器并启动
        /// </summary>
        public void InitializeChromium()
        {
            CefSettings settings = new CefSettings();
            String page = string.Format(@"{0}\ViewData\html\Index.html", Application.StartupPath);

            if (!File.Exists(page))
            {
                MessageBox.Show("Error The html file doesn't exists : " + page);
            }
           
            // Initialize cef with the provided settings
            Cef.Initialize(settings);
            // Create a browser component
            chromeBrowser = new ChromiumWebBrowser(page);

            // Add it to the form and fill it to the form window.
            this.Controls.Add(chromeBrowser);
            chromeBrowser.Dock = DockStyle.Fill;

            // Allow the use of local resources in the browser
            BrowserSettings browserSettings = new BrowserSettings();
            browserSettings.FileAccessFromFileUrls = CefState.Enabled;
            browserSettings.UniversalAccessFromFileUrls = CefState.Enabled;
            chromeBrowser.BrowserSettings = browserSettings;

        }

        /// <summary>
        /// 关闭窗口时释放浏览器资源
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            // 关闭时注销释放内核
            try
            {
                chromeBrowser.CloseDevTools();
                chromeBrowser.GetBrowser().CloseBrowser(true);
            }
            catch { }

            try
            {
                if (chromeBrowser != null)
                {
                    chromeBrowser.Dispose();
                    Cef.Shutdown();
                }
            }
            catch { }
        }

       
    }
}

后端被JS调用的注册类的代码:

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 CefSharpWinformDemo
{
    public class CefCustomObject
    {
        // Declare a local instance of chromium and the main form in order to execute things from here in the main thread
        private static ChromiumWebBrowser _instanceBrowser = null;
        // The form class needs to be changed according to yours
        private static Form1 _instanceMainForm = null;
       
        public CefCustomObject(ChromiumWebBrowser originalBrowser, Form1 mainForm)
        {
            _instanceBrowser = originalBrowser;
            _instanceMainForm = mainForm;
        }

        /// <summary>
        /// 窗口加载完毕时需要出发的全局JS对象;
        /// </summary>
        public void OnFrameLoadEnd(object sender, FrameLoadEndEventArgs e)
        {
            if (e.Frame.IsMain)
            {
                    _instanceBrowser.ExecuteScriptAsync(@"
              document.body.onmouseup = function()
              {
                bound.onSelected(window.getSelection().toString());
              }
            ");
            }
        }

        /// <summary>
        /// 显示一个弹出对话框,前端JS调用的方法
        /// </summary>
        /// <param name="msg">传入参数</param>
        public void showAlertMsg(string msg)
        {
            MessageBox.Show("The user selected some text [" + msg + "]");
        }

        public string ReadIdCard()
        {
            // 具体调用读身份证读卡器的方法
            // IDCardModel model=IDCardSdk.Read();
            //将身份证信息返回给前端;
            // return model.ToJson();
            return "调用失败";
        }
    }
}

前端html代码:

<!DOCTYPE html>
<html style="overflow: hidden;">
<head>
    <title></title>
    <link type="text/css" href="../Content/css/framework-font.css" rel="stylesheet">
    <!-- jQuery相关引用 -->
    <script type="text/javascript" src="../Content/js/jquery/jquery-2.1.1.min.js"></script>
    <script type="text/javascript" src="../Content/js/jquery/jquery.cookie.js"></script>
</head>
<body >
    <div>
        <button onclick="test1()">测试弹出框</button>
        <button onclick="test2()">读取身份证信息</button>
        身份证信息<textarea id="idcardmsg"></textarea>
    </div>
<script>
    function test1() {
        bound.showAlertMsg("测试内容");
    }

    function test2() {
        var result = bound.readIdCard();
        $("#idcardmsg").val(result);
    }

</script>
</body>
</html>

 运行之后的画面

  • 6
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 22
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值