zoukankan      html  css  js  c++  java
  • WPF浏览器应用程序与JS的互调用(不用WebBrowser)

    首先说些题外话,很久没有写博客了,空间里面的大部分文章还是11年写的。那时候刚毕业就来到这家公司,参与到一个Asp.net MVC的项目开发中,这个项目是一个全新的项目,连项目开发框架都没有,亏得领导的信任,让我研究一个MVC开发框架。那时候的我就像打了鸡血一样斗志高昂,努力奋斗了一个月后终于搭建了一个比较粗糙的Asp.net MVC+JQuery+EF4.0+Oracle的开发框架,不得不说MVC和Jquery Ajax简直就是天生一对。空间中的文章大部分都是这个时候写的。

    随后的两年,我投入到基于WPF的逻辑图项目的研发中,学习到了很多东西,业务上的就不说了;技术上包括:如何利用WPF的图形渲染优势开发一套图形引擎、通用的撤销回做组件设计、图形布局算法(花了大量的时间)、鼠标工具、图形拓扑分析联动等。由于技术保密原因,这些东西都不能写成博客公开,因此这两年我一篇博客都没写。但是最近需要开发一个WPF浏览器应用程序与外部Flex程序的交互功能,查找了很多资料都没有找到解决办法,一般都是通过WebBrowser来中转实现,这局限性不能满足要求,所以最终还是采取了JS直接与WPF函数互调用的方式来实现。

    言归正传,以下是这个问题的解决方案,希望各位不吝指教。

    WPF浏览器应用程序(xbap)实际并不是一个标准的Web应用程序,它只不是由IE中承载的PresentationHost.exe充当宿主来解析执行,原理与ActiveX类似。JS与ActiveX交互的资料网上很多,把WPF浏览器应用程序封装成ActiveX然后开发与JS的交互函数,这也可以作为我们的一种解决方案。但是我觉得这种办法太复杂了,所以没有采用。

    应用程序承载到 HTML 框架中后,您可以与包含 XBAP 的网页通信。可以通过检索 BrowserInteropHelperHostScript 属性来完成此操作。此属性会返回一个代表该 HTML 窗口的脚本对象。然后,您可以使用常规的点语法访问 window object(window 对象)的属性、方法和事件。您还可以访问脚本方法和全局变量

    上面是msdn上的一段说明,参照上面的做法:我创建了一个html页面,然后在页面中添加一个iframe,iframe的src属性指向目标xbap文件。我们确实可以在WPF的页面后台代码中取到外面html的HostScript脚本对象,并且可以通过这个脚本对象获取html页面的控件属性甚至调用它的JS函数。但是这个对象是只读的,也就是说你别想通过这个对象给外面的Html添加一个函数、事件监听什么的。

    我们的问题卡在这里了,我们已经实现了WPF调用html页面的JS函数,但是JS函数怎么样才能调用到WPF的函数呢?

    其实思路很简单,我在外面的html页面的JS部分定义一个变量wpfObj,并且定义一个设置wpfObj值的函数——SetWpfObj(wpfobj);然后在wpf页面后台构造函数中通过HostScript调用SetWpfObj函数给wpfObj复制一个C#对象,由这个对象来负责调用WPF的函数;最后JS函数执行的时候通过wpfObj调用C#对象的函数便完成了JS调用WPF函数的过程。

    通过这两种方式的结合,便完成了JS和WPF函数的互调用,而且简单易复用,当我需要与外部交互的时候,我给外部展示这个html;当我不需要这个接口的时候,我直接展示这个xbap即可。无图无真相,下面详细贴出代码设置和运行结果。

    html代码如下:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <meta http-equiv="X-UA-Compatible" content="IE=8"/> <!--不加上这一句,IE9貌似没效果-->
    <script type="text/javascript">
    //    调用WPF的JS函数
        function JSInvokeWPF() {
            if (wpfObj == null) {
                alert("中间对象为空!");
            } else {
                alert(wpfObj.MyMethod("JS调用WPF后台函数"));
            }
        }
    
    //    供WPF调用的函数
        function WPFInvokeJS(parameter) {
            alert(parameter);
        }
        var wpfObj = null;
        function SetWpfObj(obj) {
            wpfObj = obj;
        }
    
    </script>
    
    
    <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
            <title>交互测试</title>
        </head>
        <body>
            <span>
                <button title="JS调用WPF函数" style="height: 30px;  100%;" onclick=" JSInvokeWPF();return false; ">JS调用WPF函数</button>
            </span>
            <iframe id="wpf" src="OPSYS.Web_Schematic.UI.xbap" Style=" 100%;height: 540px" ></iframe>
        </body>
    </html>
    View Code

    WPF后台文件代码如下:

    using System.Runtime.InteropServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Interop;
    using MessageBox = System.Windows.MessageBox;
    
    namespace OPSYS.Web_Schematic.UI
    {
        /// <summary>
        /// ShellView.xaml 的交互逻辑
        /// </summary>
        public partial class ShellView : Page
        {
            private dynamic scriptObject = null;
            public ShellView()
            {
                InitializeComponent();
    
                // Retrieve the script object. The XBAP must be hosted in a frame or
                // the HostScript object will be null.
    
    
                if (!BrowserInteropHelper.IsBrowserHosted)
                {
                    MessageBox.Show("不满足与JS调用条件");
                    return;
                }
                scriptObject = BrowserInteropHelper.HostScript;
                if(scriptObject!=null)
                {
                    scriptObject.SetWpfObj(new CallbackClass());
                }
            }
            private void JavaScriptInvoke_Click(object sender, RoutedEventArgs e)
            {
                if(scriptObject!=null)
                scriptObject.WPFInvokeJS("WPF调用JS函数");
            }
    
        }
        //记得加上这个特性
        [ComVisible(true)]
        public class CallbackClass
        {
            public string MyMethod(string message)
            {
                return "来自WPF的中转函数," + message;
            }
        }
    }
    View Code

    运行结果如下:

    如果您发现VS老是报JS函数不存在,请设置如下内容(请运行在IE8模式):

  • 相关阅读:
    hdu5360 Hiking(水题)
    hdu5348 MZL's endless loop(欧拉回路)
    hdu5351 MZL's Border(规律题,java)
    hdu5347 MZL's chemistry(打表)
    hdu5344 MZL's xor(水题)
    hdu5338 ZZX and Permutations(贪心、线段树)
    hdu 5325 Crazy Bobo (树形dp)
    hdu5323 Solve this interesting problem(爆搜)
    hdu5322 Hope(dp)
    Lightoj1009 Back to Underworld(带权并查集)
  • 原文地址:https://www.cnblogs.com/yuananyun/p/3523772.html
Copyright © 2011-2022 走看看