• 热门专题

CefSharp初识把网页移到桌面

作者:stoneniqiu  发布日期:2016-01-06 19:57:12
Tag标签:桌面  网页  
  • 在开发中我们可曾有过这样的需求,将某个网页嵌入到.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;
            }
        }

    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() + '
    ';
                    }
                </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() + '
    ';
     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;
            }
        }

    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() + '
    ';
                    }
                </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() + '
    ';
    
                        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的支持确实不错。后续有机会做更多分享。 

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规