http://blog.csdn.net/lllllllllluoyi/article/details/8540054

首先向360说句sorry,在2011年360极速浏览器出现的时候我去他们论坛里骂过。为什么要到歉呢,因为2012年我把我们公司使用IE WebBrowser改为Chrome控件了,中间遇到的辛酸使我明白360公司能做成产品确实不容易。言归正转,公司的壳程序是C#编写的WinForm程序,刚开始我只找到delphi的Chromium项目,然后在delphi2010中安装好控件后就生成DLL让WinForm程序调用,这种策略是我做这个控件的最大失败。因为我对delphi比较熟,很快控件就能在WinForm程序里跑起来了,很开心,立马根据壳中已经使用的事件和方法在自定义控件中实现,自测一下没有问题后就交给测试人员来试用,半天的功夫,测试员小张就来对我说:罗兄,网页中不能使用键盘上Tab键切换,回车事件响应不了......不会吧,是不是焦点没有定位到自定义控件中,我第一时间就是这样想,然后就是反复的折腾,还是不行。最后Google了一下,好不容易找到一个让自己信服的答案,就是win32的消息循环机制与.net消息机制不一样,嵌入到WinForm中的VCL控件不能得到消息。我靠,这还得了,leader还不把我劈了,leader已经吩咐美工全按chrome浏览器的样式来写了。兵来将挡,水来土淹,我火速Google一个能在.net上跑的版本“CefSharp”  ,下载来看,傻眼了,是C++版的,咋办?熬夜啃吧!

我分为了两个项目,一是libfuncs,为了使DLL名称一致,我重命名了CefSharp项目,它负责提供操作浏览器的方法和触发事件;二是cwber,它是自定义的WinForm控件,用于在Form上的布局,必须引用libfuncs.dll。

源码地址:https://sourceforge.net/projects/chromewebbrowse

cwber比较简单,以下是它的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using libfuncs; namespace cwber
{
public partial class ChromeWebBrowser : UserControl
{
private ChromeApp chrome = null;
ToolTip myToolTip = new ToolTip();
public ChromeWebBrowser()
{
InitializeComponent();
ChromeWebBrowser.CheckForIllegalCrossThreadCalls = false;
} private void ChromeWebBrowser_Load(object sender, EventArgs e)
{
if (chrome == null)
{
chrome = new ChromeApp();
}
Start(); } #region 外部调用方法
libfuncs.DocumentCompletedEvent elementEvent1;
libfuncs.FrameLoadStartEvent elementEvent2;
libfuncs.FrameLoadEndEvent elementEvent3;
libfuncs.FileDownloadingEvent fileDownloading;
libfuncs.FileDownloadCompletedEvent fileDownloaded;
libfuncs.ComponentInitialized componentInitialized;
libfuncs.ToolTipEventListener toolTipEvent;
public void Start()
{
if (chrome != null)
{
chrome.Dock = DockStyle.Fill; if (componentInitialized == null)
{
componentInitialized = new libfuncs.ComponentInitialized(componentInitializedEvent);
chrome.RegisterEvent(componentInitialized);
}
Controls.Add(chrome);
if (elementEvent1 == null)
{
elementEvent1 = new libfuncs.DocumentCompletedEvent(documentComplete);
chrome.RegisterEvent(elementEvent1);
}
if (elementEvent2 == null)
{
elementEvent2 = new libfuncs.FrameLoadStartEvent(frameStartStart);
chrome.RegisterEvent(elementEvent2);
}
if (elementEvent3 == null)
{
elementEvent3 = new libfuncs.FrameLoadEndEvent(frameLoadEnd);
chrome.RegisterEvent(elementEvent3);
}
if (fileDownloading == null)
{
fileDownloading = new libfuncs.FileDownloadingEvent(this.downloading);
chrome.RegisterEvent(fileDownloading);
}
if (fileDownloaded == null)
{
fileDownloaded = new libfuncs.FileDownloadCompletedEvent(this.downloaded);
chrome.RegisterEvent(fileDownloaded);
}
if (toolTipEvent == null)
{
toolTipEvent = new libfuncs.ToolTipEventListener(this.ShowToolTipText);
chrome.RegisterEvent(toolTipEvent);
} chrome.Visible = true;
chrome.BringToFront();
}
}
/*
* 描述:释放浏览器
*/
public void Free()
{
elementEvent1 = null;
elementEvent2 = null;
elementEvent3 = null;
fileDownloading = null;
fileDownloaded = null;
componentInitialized = null;
toolTipEvent = null;
chrome.Dispose();
chrome = null;
}
/*
* 参数:Url 打开网页地址
* 描述:打开网址。
*/
public void OpenUrl(string Url)
{
if (chrome != null)
chrome.Load(Url);
}
/*
* 参数:id 网页中的控件元素ID
* 描述:根据元素ID获取元素的值,适用于Input,A标签元素
*/
public string GetElementValueById(string id)
{
return chrome == null ? "" : chrome.GetElementValueById(id);
}
/*
* 参数:id 网页中的控件元素ID, value 元素新值
* 描述:为页面中元素赋予新值。
*/
public void SetElementValueById(string id, string value)
{
if (chrome != null)
{
chrome.SetElementValueById(id, value);
}
} public delegate void TCallBackElementEventListener();
private List<libfuncs.ElementEventListener> elementEventList = new List<libfuncs.ElementEventListener>();
/*
* 描述:附加元素的侦听事件。当该元素触发附加事件时,则执行TCallBackElementEventListener委托方法
*/
public void AppendElementEventListener(string id, string eventName, TCallBackElementEventListener callFunc)
{
libfuncs.ElementEventListener elementEvent = new libfuncs.ElementEventListener(callFunc);
elementEventList.Add(elementEvent);
chrome.AddElementEventListener(id, eventName, elementEvent);
}
/*
* 描述:向页面中注入并执行脚本。
*/
public void ExecuteScript(string script)
{
if (chrome != null)
chrome.ExecuteScript(script);
} public object EvaluateScript(string script)
{
if (chrome != null)
return chrome.EvaluateScript(script);
else
return null;
} /*
* 描述:计算文件单位。用于文件下载。
*/
private string CompareFileSize(Int64 size)
{
//计算K,M单位
string strTotalSize = string.Empty;
if (size < )
{
strTotalSize = size.ToString() + " B";
}
else if (size >= && size < * )
{
strTotalSize = (size / ).ToString() + " KB";
}
else
{
strTotalSize = (size / / ).ToString() + " MB";
}
return strTotalSize;
} #endregion #region 属性
public string Url
{
get
{
return chrome == null?"":chrome.Core.Address;
}
}
#endregion #region 事件
/*控件初始化事件*/
public event EventHandler ComponentInitializedEventHandler;
private void componentInitializedEvent()
{
EventArgs e = new EventArgs();
if (ComponentInitializedEventHandler != null)
ComponentInitializedEventHandler(this, e);
}
/*页面加载完成事件*/
public event EventHandler DocumentCompletedEventHandler;
private void documentComplete()
{
EventArgs e = new EventArgs();
if (DocumentCompletedEventHandler != null)
DocumentCompletedEventHandler(this, e);
}
/*Frame加载完成事件,这里的Frame可以是页面本身,也是iFrame元素*/
public event EventHandler PageLoadFinishEventHandler;
private void frameLoadEnd()
{
EventArgs e = new EventArgs();
if (PageLoadFinishEventHandler != null)
PageLoadFinishEventHandler(this, e);
}
/*Frame加载开始事件,这里的Frame可以是页面本身,也是iFrame元素*/
public event EventHandler PageLoadStartEventHandler;
private void frameStartStart()
{
EventArgs e = new EventArgs();
if (PageLoadStartEventHandler != null)
PageLoadStartEventHandler(this, e);
}
/*下载中事件,不开放该事件*/
Form downloadForm = null;
private void downloading(Int64 totalSize, Int64 loadedSize)
{
string strTotalSize = CompareFileSize(totalSize);
string strLoadedSize = CompareFileSize(loadedSize); if (downloadForm == null)
{
downloadForm = new Form();
downloadForm.Text = "下载中";
downloadForm.Width = ;
downloadForm.Height = ;
downloadForm.MaximizeBox = false;
downloadForm.MinimizeBox = false;
downloadForm.ControlBox = false;
downloadForm.StartPosition = FormStartPosition.CenterScreen; Label label = new Label();
label.Left = ;
label.Top = ;
label.Width = ;
label.Text = "已下载:" + strLoadedSize + "/" + strTotalSize;
downloadForm.Controls.Add(label);
}
downloadForm.Show();
downloadForm.BringToFront();
foreach (Control c in downloadForm.Controls)
{
if (c is Label)
{
Label label = (Label)c;
label.Text = "已下载:" + strLoadedSize + "/" + strTotalSize;
label.Update();
}
}
downloadForm.Update();
}
/*下载完成事件,不开放该事件*/
private void downloaded()
{
if (downloadForm != null)
downloadForm.Close();
downloadForm = null;
}
/*消息提示事件,不开放*/
private void ShowToolTipText(string text)
{
if (chrome == null) return;
if (string.IsNullOrEmpty(text))
{
myToolTip.RemoveAll();
return;
}
//保证每行40个字
int len = text.Length;
int offset = ;
int count = len / offset;
for (int i = ; i <= count; i++)
{
text = text.Insert(offset * i, "\n");
}
myToolTip.ShowAlways = false;
myToolTip.UseAnimation = true;
myToolTip.UseFading = true;
//t.SetToolTip(button1, text);
Point p = Control.MousePosition;
Point p1 = this.PointToClient(p);
myToolTip.Show(text, chrome, p1.X+, p1.Y+);
}
#endregion
}
}

重点是libfuncs中的libfuncs.h、ChromeApp.h、ChromeApp.cpp、ClientAdapter.h、ClientAdapter.cpp五个文件,实现方法都在里面,其他的文件基本都是接口文件。我自己只根据项目实际需求来做的功能,接口没有全部实现。这个部分大家看源代码吧,我用到的地方都注释了。文采不行,写不动,大家原谅。睡了。

最后说句,我们公司网页美工解脱了!

基于Chromium构建Chrome WebBrowser for .net 控件(还有点心得体会)的更多相关文章

  1. 如何通过JavaScript构建Asp.net服务端控件

    摘要 虽然ASP.NET的服务器控件一直被大家所诟病,但是用户控件(ACSX)在某些场景下还是非常有用的. 在一些极特珠的情况下,我们会使用JavaScript动态的构建页面中的控件,但假设遇到了我要 ...

  2. 基于jquery的可查询多级select控件(可记录历史选择)

    一.功能和使用 公司有功能需求,还要一条代码引入的控件,网上找完全符合的控件比较难,寻找所花的时间还不如自己写一个,所以找个空闲时间自己写了一个   控件功能:1.可手动输入查询,也可点击下拉框查询, ...

  3. 基于avalon+jquery做的bootstrap分页控件

    刚开始学习avalon,项目需要就尝试写了个分页控件Pager.js:基于BootStrap样式这个大家都很熟悉 在这里推荐下国产前端神器avalon:确实好用,帮我解决了很多前端问题. 不多说了,代 ...

  4. 文档驱动 —— 表单组件(五):基于Ant Design Vue 的表单控件的demo,再也不需要写代码了。

    源码 https://github.com/naturefwvue/nf-vue3-ant 特点 只需要更改meta,既可以切换表单 可以统一修改样式,统一升级,以最小的代价,应对UI的升级.切换,应 ...

  5. 基于C#语言MVC框架Aspose.Cells控件导出Excel表数据

    控件bin文件下载地址:https://download.csdn.net/download/u012949335/10610726 @{ ViewBag.Title = "xx" ...

  6. 基于WPF系统框架设计(10)-分页控件设计

    背景 最近要求项目组成员开发一个通用的分页组件,要求是这个组件简单易用,通用性,兼容现有框架MVVM模式,可是最后给我提交的成果勉强能够用,却欠少灵活性和框架兼容性. 设计的基本思想 传入数据源,总页 ...

  7. 基于 mpvue 框架的小程序选择控件,支持单列,多列,联动

    最近在学着写mpvue小程序,在做选择控件时候遇到了点问题,按照微信小程序方法picker,很不方便! 在网上搜到一个很好用的组件下面给大家分享: 组件说明文档链接:https://go.ctolib ...

  8. chrome新版安装flash控件失败解决方法

    今天chrome打开后出现插件过期,之后更新一直安装失败 度娘找到一个方法: 1.下载flash最新版for chrome : https://fpdownload.macromedia.com/pu ...

  9. 构建基于WinRT的WP8.1 App 03:Page控件

    单页面模板 通常利用Visual Studio 2013创建的最简单的WP8.1应用是Blank App,它只包含一个不带任何UI的页面,并且没有任何状态管理的逻辑. 该不带任何UI的页面称为Blan ...

随机推荐

  1. mfc中CString转化为string的方法

    LL(1)分析法实验的mfc做到最后因为CString转化为string的问题卡了一个多小时,也是惨,网上各种方法找过都不行.幸亏最后还是找到几行代码搞定了.特此mark一下. USES_CONVER ...

  2. Linux下一些文件夹的含义

    在 Linux系统里面,"分区",被称作"挂载点",简单明了的说,"挂载点"意思就是:把一部分硬盘容量,"分"成一个文件 ...

  3. Til the Cows Come Home

    Description Bessie is out in the field and wants to get back to the barn to get as much sleep as pos ...

  4. php执行流程

    1.源码文件编写,php源文件 2.词法分析,token 3.语法分析,生成opcode并组成opcode array 4.执行opcode,返回结果

  5. Spring AOP小结

    一. AOP介绍 AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP ...

  6. 【kd-tree】bzoj3053 The Closest M Points

    同p2626.由于K比较小,所以不必用堆. #include<cstdio> #include<cstring> #include<cmath> #include& ...

  7. C++二级指针第二种内存模型(二维数组)

    C++二级指针第二种内存模型(二维数组) 二维数组 二维数组本质上是以数组作为数组元素的数组,即“数组的数组”. 定义 类型说明符 数组名[常量表达式][常量表达式] 例如: float a[3][4 ...

  8. PHP部分字符串函数汇总

    PHP部分字符串函数汇总 提交 我的评论 加载中 已评论 PHP部分字符串函数汇总 2015-03-10 PHP100中文网 PHP100中文网 PHP100中文网 微信号 功能介绍 互联网开发者社区 ...

  9. 某些版本的IIS可能有SessionID混淆的Bug

    某公司为我服务的甲方公司开发一个挺重要的应用.已经上线了一年多了,不停的修修改改.也算正常使用.正所谓,秀恩爱,死得快.No 作就No Die.也少知道是那个Smarty Pants闲的蛋疼说新修改的 ...

  10. jenkins 插件Copy Artifacts + Artifacts to copy

    问题及遇到的错误: Unable to access upstream artifacts area /var/lib/jenkins/jobs/PROJECTNAME-Master-Branch/b ...