CefSharp初识--把网页移到桌面的神器

jopen 8年前

在开发中我们可曾有过这样的需求,将某个网页嵌入到.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[] { 7, 8 }; }          }            public int[] MyIntArray          {              get { return new[] { 1, 2, 3, 4, 5, 6, 7, 8 }; }          }            public Array MyArray          {              get { return new short[] { 1, 2, 3 }; }          }            public byte[] MyBytes          {              get { return new byte[] { 3, 4, 5 }; }          }            public BoundObject()          {              MyProperty = 42;              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 = 1500;                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 = 0; 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;          }      }    View Code

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 = 1500;                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 = 0; 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;          }      }    View Code

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>    View Code

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的支持确实不错。后续有机会做更多分享。

来自: http://www.cnblogs.com/stoneniqiu/p/5089986.html