在开发中我们可曾有过这样的需求,将某个网页嵌入到.Net应用中来,但Winform自带的web browser不怎么理想。CefSharp可以让我们在.Net应用中嵌入一个Chromium。它提供了WPF和Winform版的web browser 控件,能很好的渲染出HTML5效果而且和宿主程序有很强的交互能力。  git地址:https://github.com/cefsharp/CefSharp 。

在WPF中使用

在Nugget中输入CefSharp,找到CefSharp.WPF 并按照到工程中。

cefsharp不支持anycup,还需要设置一下目标平台为x86或x64. 具体请移步:http://www.cnblogs.com/yuefei/p/4123597.html

渲染效果

加入一个css3的动画:转动的风车。 元素结构还是很清晰,但动画效果还是没有浏览器流畅。

交互方法

cefsharp支持JavaScript和C#方法相互调用。首先需要注册一个绑定对象:

  private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
var wb = new ChromiumWebBrowser
{
Address = @"file:///D:/VS2012/Support/Main/Portal/Presentation/Portal.Client/Resources/BindingTest.html"
};
wb.RegisterJsObject("bound", new BoundObject());
WBGrid.Children.Add(wb);
}

BoundObject:

 public class BoundObject
{
public int MyProperty { get; set; } public string MyReadOnlyProperty { get; internal set; }
public Type MyUnconvertibleProperty { get; set; }
public SubBoundObject SubObject { get; set; }
public ExceptionTestBoundObject ExceptionTestObject { get; set; } public uint[] MyUintArray
{
get { return new uint[] { , }; }
} public int[] MyIntArray
{
get { return new[] { , , , , , , , }; }
} public Array MyArray
{
get { return new short[] { , , }; }
} public byte[] MyBytes
{
get { return new byte[] { , , }; }
} public BoundObject()
{
MyProperty = ;
MyReadOnlyProperty = "I'm immutable!";
IgnoredProperty = "I am an Ignored Property";
MyUnconvertibleProperty = GetType();
SubObject = new SubBoundObject();
ExceptionTestObject = new ExceptionTestBoundObject();
} public void TestCallback(IJavascriptCallback javascriptCallback)
{
const int taskDelay = ; Task.Run(async () =>
{
await Task.Delay(taskDelay); await javascriptCallback.ExecuteAsync("This callback from C# was delayed " + taskDelay + "ms");
});
} public int EchoMyProperty()
{
return MyProperty;
} public string Repeat(string str, int n)
{
string result = String.Empty;
for (int i = ; i < n; i++)
{
result += str;
}
return result;
} public string EchoParamOrDefault(string param = "This is the default value")
{
return param;
} public void EchoVoid()
{
} public Boolean EchoBoolean(Boolean arg0)
{
return arg0;
} public Boolean? EchoNullableBoolean(Boolean? arg0)
{
return arg0;
} public SByte EchoSByte(SByte arg0)
{
return arg0;
} public SByte? EchoNullableSByte(SByte? arg0)
{
return arg0;
} public Int16 EchoInt16(Int16 arg0)
{
return arg0;
} public Int16? EchoNullableInt16(Int16? arg0)
{
return arg0;
} public Int32 EchoInt32(Int32 arg0)
{
return arg0;
} public Int32? EchoNullableInt32(Int32? arg0)
{
return arg0;
} public Int64 EchoInt64(Int64 arg0)
{
return arg0;
} public Int64? EchoNullableInt64(Int64? arg0)
{
return arg0;
} public Byte EchoByte(Byte arg0)
{
return arg0;
} public Byte? EchoNullableByte(Byte? arg0)
{
return arg0;
} public UInt16 EchoUInt16(UInt16 arg0)
{
return arg0;
} public UInt16? EchoNullableUInt16(UInt16? arg0)
{
return arg0;
} public UInt32 EchoUInt32(UInt32 arg0)
{
return arg0;
} public UInt32? EchoNullableUInt32(UInt32? arg0)
{
return arg0;
} public UInt64 EchoUInt64(UInt64 arg0)
{
return arg0;
} public UInt64? EchoNullableUInt64(UInt64? arg0)
{
return arg0;
} public Single EchoSingle(Single arg0)
{
return arg0;
} public Single? EchoNullableSingle(Single? arg0)
{
return arg0;
} public Double EchoDouble(Double arg0)
{
return arg0;
} public Double? EchoNullableDouble(Double? arg0)
{
return arg0;
} public Char EchoChar(Char arg0)
{
return arg0;
} public Char? EchoNullableChar(Char? arg0)
{
return arg0;
} public DateTime EchoDateTime(DateTime arg0)
{
return arg0;
} public DateTime? EchoNullableDateTime(DateTime? arg0)
{
return arg0;
} public Decimal EchoDecimal(Decimal arg0)
{
return arg0;
} public Decimal? EchoNullableDecimal(Decimal? arg0)
{
return arg0;
} public String EchoString(String arg0)
{
return arg0;
} // TODO: This will currently not work, as it causes a collision w/ the EchoString() method. We need to find a way around that I guess.
//public String echoString(String arg)
//{
// return "Lowercase echo: " + arg;
//} public String lowercaseMethod()
{
return "lowercase";
} public string ReturnJsonEmployeeList()
{
return "{\"employees\":[{\"firstName\":\"John\", \"lastName\":\"Doe\"},{\"firstName\":\"Anna\", \"lastName\":\"Smith\"},{\"firstName\":\"Peter\", \"lastName\":\"Jones\"}]}";
} [JavascriptIgnore]
public string IgnoredProperty { get; set; } [JavascriptIgnore]
public string IgnoredMethod()
{
return "I am an Ignored Method";
} public string ComplexParamObject(object param)
{
if (param == null)
{
return "param is null";
}
return "The param type is:" + param.GetType();
} public SubBoundObject GetSubObject()
{
return SubObject;
}
}

JavaScript调用C#方法并执行回调函数:

  <p>
Javscript Callback Test
<br />
<script type="text/javascript">
function callback(s)
{
var result = document.getElementById('cbresult');
result.innerText += "Callback: " + s+ "" + Date();
} function testCallback()
{
bound.testCallback(callback); var result = document.getElementById('cbresult');
result.innerText = "The function has returned: " + Date() + "\n";
}
</script>
<button onclick="testCallback()">Test Callback</button>
<br />
<span id="cbresult"></span>
</p>

这里的bound就是我们注册的C#对象。其中包含一个TestCallback的方法。调用的时候不区分大小写。

  public void TestCallback(IJavascriptCallback javascriptCallback)
{
const int taskDelay = ; Task.Run(async () =>
{
await Task.Delay(taskDelay); using (javascriptCallback)
{
await javascriptCallback.ExecuteAsync("This callback from C# was delayed " + taskDelay + "ms");
}
});
}

执行结果:

先执行了testCallback方法,然后执行了callback,返回了后台传递过来的参数。但如果再执行JavaScript之后页面跳转了,是不会再执行C#里面的回调函数的。

 function testDisposedCallback()
{
bound.testCallback(callback); //这里的方法不会执行了。
var result = document.getElementById('disposedcbresult');
result.innerText = "The function has returned: " + Date() + "\n";
window.location.assign("http://www.baidu.com");
}

JavaScript执行有参数的C#方法

BoundObject有一个Repeat方法

   public string Repeat(string str, int n)
{
string result = String.Empty;
for (int i = ; i < n; i++)
{
result += str;
}
return result;
}

JavaScript调用:

 <p>
Result of calling bound.repeat("hi ", 5) =
<script type="text/javascript">
var result = bound.repeat("hi ", 5);
document.write('"' + result + '"');
if (result === "hi hi hi hi hi ")
{
document.write(" SUCCESS");
} else
{
document.write(" FAIL!");
}
</script>
</p>

执行结果:

委托C#方法

将绑定对象的方法作为参数传递给JavaScript方法。

  <script type="text/javascript">
function myFunction(functionParam)
{
return functionParam();
}
document.write("委托输出属性结果: " + myFunction(bound.echoMyProperty));
</script>
echoMyProperty方法:
   public int EchoMyProperty()
{
return MyProperty;//初始化为42
}

返回C#对象

BoundObject含有一个子对象 SubBoundObject。通过GetObject返回。

 public SubBoundObject GetSubObject()
{
return SubObject;
}

SubBoundObject:

public class SubBoundObject
{
public string SimpleProperty { get; set; } public SubBoundObject()
{
SimpleProperty = "这是子对象属性";
} public string GetMyType()
{
return "My Type is " + GetType();
} public string EchoSimpleProperty()
{
return SimpleProperty;
}
}

JavaScript调用:

 <script type="text/javascript">
document.write("bound.getSubObject().simpleProperty result: " + bound.getSubObject().simpleProperty);
</script>

执行结果:

获取bound对象的所有方法和属性

        'bound的'所有方法:<br />
<ul>
<script type="text/javascript">
for (var name in bound)
{
if (bound[name].constructor.name != 'Function') continue;
document.write("<li>" + name + "</li>");
}
</script>
</ul> 'bound的'所有属性:<br />
<ul>
<script type="text/javascript">
for (var name in bound)
{
if (bound[name].constructor.name === 'Function') continue; document.write("<li>" + name + "</li>");
if (typeof bound[name] == "object" && bound[name] !== null)
{
//展示子对象属性
for (var sub in bound[name])
{
var type = bound[name][sub].constructor.name === 'Function' ? "Function" : "Property";
document.write("<li>" + name + "." + sub + "(" + type + ")" + "</li>");
}
}
}
</script>
</ul>

可以在C#对象中忽略掉属性和方法,这样就不会显示出来。

   [JavascriptIgnore]
public string IgnoredProperty { get; set; } [JavascriptIgnore]
public string IgnoredMethod()
{
return "I am an Ignored Method";
}

整个测试页面:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Binding Test</title>
</head>
<body>
<p>
Async Binding Test
<span id="asyncresult"></span>
<script type="text/javascript">
var asResult = document.getElementById('asyncresult'); function writeAsyncResult(call, end)
{
var p = document.createElement('p');
var br = document.createElement('br');
var br2 = document.createElement('br');
var title = document.createTextNode('Async Call: ');
var callText = document.createTextNode(call);
var endText = document.createTextNode(end); p.appendChild(title);
p.appendChild(br);
p.appendChild(callText);
p.appendChild(br2);
p.appendChild(endText); asResult.appendChild(p);
} function asyncError()
{
var call = "Async call (Throw Exception): " + Date();
boundAsync.error().catch(function (e)
{
var end = "Error: " + e + "(" + Date() + ")";
writeAsyncResult(call, end);
});
} function asyncDivOk()
{
var call = "Async call (Divide 16 / 2): " + Date();
boundAsync.div(16, 2).then(function (res)
{
var end = "Result: " + res + "(" + Date() + ")";
writeAsyncResult(call, end);
});
} function asyncDivFail()
{
var call = "Async call (Divide 16 /0): " + Date();
boundAsync.div(16, 0).then(function (res)
{
var end = "Result: " + res + "(" + Date() + ")";
writeAsyncResult(call, end);
},
function (e)
{
var end = "Error: " + e + "(" + Date() + ")";
writeAsyncResult(call, end);
});
} function asyncHello()
{
var call = "Async call (Hello): " + Date();
boundAsync.hello('CefSharp').then(function (res)
{
var end = "Result: " + res + "(" + Date() + ")";
writeAsyncResult(call, end);
});
} function asyncDoSomething()
{
var call = "Async call (Long Running Task): " + Date();
boundAsync.doSomething().then(function (res)
{
var end = "Result: " + res + "(" + Date() + ")";
writeAsyncResult(call, end);
});
} asyncError();
asyncDivOk();
asyncDivFail();
asyncDoSomething();
</script>
</p>
<p>
Javscript Callback Test
<br />
<script type="text/javascript">
function callback(s) {
var result = document.getElementById('cbresult');
result.innerText += "Callback: " + s + "" + Date();
} function testCallback()
{
bound.testCallback(callback);
var result = document.getElementById('cbresult');
result.innerText = "The function has returned: " + Date() + "\n";
}
</script>
<button onclick="testCallback()">Test Callback</button>
<br />
<span id="cbresult"></span>
</p> <p>
Disposed Javscript Callback Test (navigates to www.google.com before callback fires)
<br />
<script type="text/javascript">
function disposedCallback(s)
{
// This callback should be disposed and should not be called
window.alert("This callback should not have been called"); var result = document.getElementById('disposedcbresult');
result.innerText += "Callback: " + s + "" + Date();
} function testDisposedCallback()
{
bound.testCallback(callback); var result = document.getElementById('disposedcbresult');
result.innerText = "The function has returned: " + Date() + "\n"; window.location.assign("http://www.baidu.com");
}
</script>
<button onclick="testDisposedCallback()">Test Disposed Callback</button>
<br />
<span id="disposedcbresult"></span>
</p> <p>
Result of calling bound.repeat("hi ", 5) =
<script type="text/javascript">
var result = bound.repeat("hi ", 5);
document.write('"' + result + '"');
if (result === "hi hi hi hi hi ")
{
document.write(" SUCCESS");
} else
{
document.write(" FAIL!");
}
</script>
</p> <p>
委托c# 方法
<br />
<script type="text/javascript">
function myFunction(functionParam)
{
return functionParam();
}
document.write("委托输出属性结果: " + myFunction(bound.echoMyProperty));
</script>
</p> <p>
Function returning complex type
<br />
<script type="text/javascript">
document.write("bound.getSubObject().simpleProperty result: " + bound.getSubObject().simpleProperty);
</script>
</p> <p>
Stress Test
<br />
<script type="text/javascript">
var stressTestCallCount = 1000;
for (var i = 1; i <= stressTestCallCount; i++)
{
bound.repeat("hi ", 5);
} document.write("Stress Test done with : " + stressTestCallCount + " call to bound.repeat(\"hi \", 5)");
</script>
</p> <p>
JSON Serializer Test
<br />
<script type="text/javascript">
var json = bound.returnJsonEmployeeList();
var jsonObj = JSON.parse(json); document.write("Employee Count : " + jsonObj.employees.length + "<br/>"); for (var i = 0; i < jsonObj.employees.length; i++)
{
var employee = jsonObj.employees[i];
document.write("Employee : " + employee.firstName + " " + employee.lastName + "<br/>");
}
</script>
</p> 'bound的'所有方法:<br />
<ul>
<script type="text/javascript">
for (var name in bound)
{
if (bound[name].constructor.name != 'Function') continue;
document.write("<li>" + name + "</li>");
}
</script>
</ul> 'bound的'所有属性:<br />
<ul>
<script type="text/javascript">
for (var name in bound)
{
if (bound[name].constructor.name === 'Function') continue; document.write("<li>" + name + "</li>");
if (typeof bound[name] == "object" && bound[name] !== null)
{
//展示子对象属性
for (var sub in bound[name])
{
var type = bound[name][sub].constructor.name === 'Function' ? "Function" : "Property";
document.write("<li>" + name + "." + sub + "(" + type + ")" + "</li>");
}
}
}
</script>
</ul>
</body>
</html>

WebGL的渲染效果

WebGL是一种3D绘图标准,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTML5 Canvas提供硬件3D加速渲染,这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化。

测试页面:http://webglsamples.org/aquarium/aquarium.html

这个效果还是不错的。

小结:以上只是简单的测试程序,CEFSharp对html5和JavaScript的支持确实不错。后续有机会做更多分享。

CefSharp初识--把网页移到桌面的更多相关文章

  1. nativefier(一行代码将任意网页转化为桌面应用)

    刚刚在看前端九部的手册的时候,发现一个之前没有用过的骚东西,看上去还挺好用,我这个好奇心瞬间就窜的老高了,赶紧试一试,看看这个东西有没有必要收入我的胯下 结果实验完了之后, 必须必须要强行安利给你们 ...

  2. 网页程序 vs 桌面程序

    网页程序 vs 桌面程序 阅读:  评论:  作者:Rybby  日期:  来源:rybby.com 所谓的网页程序就是指以网页作为程序的操作界面,通过脚本语言“javascript”或其它客户端语言 ...

  3. Electron把网页打包成桌面应用并进行源码加密

    前言 最近想把自己用html+css+js做的网页界面打包成桌面应用,网上一搜,发现Electron是一个不错的选择,试了试,发现效果真的不错.这里记录一下打包过程以作记录,便于自己以后查看学习. 一 ...

  4. 【WPF】使用CefSharp嵌入HTML网页

    需求:WPF项目中要做用户的商铺主页,由于考虑到每个商家的主页布局各不相同,不能用XAML写死布局.最好的办法是WPF这边XAML写好一个容器,用户使用HTML可视化编辑器(比如这个)来准备好网页,输 ...

  5. Java Web开发技术教程入门-初识动态网页

    这段时间学校搞了一个"阅战阅勇"的阅读活动,奖品还是挺丰富的~于是,奔着这些奖品,我去图书馆借了这本<Java Web开发技术教程>.一是为了那些丰富的奖品,二是为了回 ...

  6. 设置iPhone网页固定到桌面上的图标

    <!--IOS Icon--> <link rel="apple-touch-icon-precomposed" href="@Url.Content( ...

  7. Winform下CefSharp的引用、配置、实例与报错排除(源码)

    Winform下CefSharp的引用.配置.实例与报错排除 本文详细介绍了CefSharp在vs2013..net4.0环境下,创建Winfrom项目.引用CefSharp的方法,演示了winfro ...

  8. CefSharp的引用、配置、实例

    CefSharp的引用.配置.实例与报错排除(源码) Winform下CefSharp的引用.配置.实例与报错排除 本文详细介绍了CefSharp在vs2013..net4.0环境下,创建Winfro ...

  9. Open Source

    资源来源于http://www.cnblogs.com/Leo_wl/category/246424.html RabbitMQ 安装与使用 摘要: RabbitMQ 安装与使用 前言 吃多了拉就是队 ...

随机推荐

  1. [NHibernate]查看NHibernate生成的SQL语句

    最近接触到一个用Spring.Net结合NHIbernate的项目,第一次使用,有很多配置,数据操作一旦出问题,很难找到原因,那么如何查看NHibernate发送给数据库的SQL语句呢? 当然我们可以 ...

  2. Shell_2 语句

    1 if else fi if 语句通过关系运算符判断表达式的真假来决定执行哪个分支.Shell 有三种 if ... else 语句: if ... fi 语句: if ... else ... f ...

  3. Daily Scrum Meeting ——ThirdDay(Beta)12.11

    一.Daily Scrum Meeting照片 二.Burndown Chart 三.项目进展(check-in) 1.欢迎界面的优化,从模糊到清楚 2.新增主界面背景 3.新增注册背景 4.参与者侧 ...

  4. 好用的绿色工具(mss2sql,jd-gui)

    1.sql server导入mysql 神器(速度不是一般的快) mss2sql.exe 2.java 反序列化工具 jd-gui.exe

  5. Navicat备份远程Oracle数据库到本地

    公司的数据库是本地的,我只能在公司连,回家就不能跑项目了,一跑就报SQLException,所以希望可以把数据库复制到我的本地来. 因为一直在用Navicat操作数据库,这里就分享一下用Navicat ...

  6. 关于XML中:XmlNode和XmlElement的涵义及不同之处

    今天学习XML,遇到XmlNode和XmlElement俩个类,故有了下文的所述: 今天在做ASP.NET操作XML文档的过程中,发现了两个类:XmlNode和XmlElement.这两个类的功能极其 ...

  7. 0421 & SX2016

    山西省选...这个省...不算强吧...然而就是这么腊鸡题目还是wa得一无是处...怎么办啊怎么办啊...无处拯救青春和未来啊... T1: POI2004原题 BZOJ1524 n<=16.这 ...

  8. spark shuffle 相关细节整理

    1.Shuffle Write 和Shuffle Read具体发生在哪里 2.哪里用到了Partitioner 3.何为mapSideCombine 4.何时进行排序 之前已经看过spark shuf ...

  9. 如何让{dede:channel}有子栏目显示子栏目,无子栏目不显示同级栏目

    我们在使用织梦系统制作网站时经常会遇到网站栏目较多,显示当前栏目下的二级与三级栏目时,使用栏目嵌套标签,但是当三级栏目为空时,会显示同级栏目.从用户体验角度出发,常理情况下也是需要空白的,即二级栏目下 ...

  10. ajax 后台正常执行 错误类型却是404

    后台执行importExcel,明明方法执行成功,但是前台却提示404 @RequestMapping("/import") public Json importExcel(@Re ...