CefSharp初识--把网页移到桌面

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

在WPF中使用

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

CefSharp初识--把网页移到桌面_第1张图片

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

渲染效果

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

CefSharp初识--把网页移到桌面_第2张图片      

 交互方法

 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 Callbackbutton>
            <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("
  • " + name + "
  • "); } script> ul> 'bound的'所有属性:<br /> <ul> <script type="text/javascript"> for (var name in bound) { if (bound[name].constructor.name === 'Function') continue; document.write("
  • " + name + "
  • "); 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("
  • " + name + "." + sub + "(" + type + ")" + "
  • "); } } } 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 Testtitle>
        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 Callbackbutton>
                <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 Callbackbutton>
                <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 + "
    "); for (var i = 0; i < jsonObj.employees.length; i++) { var employee = jsonObj.employees[i]; document.write("Employee : " + employee.firstName + " " + employee.lastName + "
    "); } script> p> 'bound的'所有方法:<br /> <ul> <script type="text/javascript"> for (var name in bound) { if (bound[name].constructor.name != 'Function') continue; document.write("
  • " + name + "
  • "); } script> ul> 'bound的'所有属性:<br /> <ul> <script type="text/javascript"> for (var name in bound) { if (bound[name].constructor.name === 'Function') continue; document.write("
  • " + name + "
  • "); 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("
  • " + name + "." + sub + "(" + type + ")" + "
  • "); } } } 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的支持确实不错。后续有机会做更多分享。 

     

    你可能感兴趣的:(CefSharp初识--把网页移到桌面)