• 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模式):

  • 相关阅读:
    java返回json数据日期为一串数字字符串 js 转义
    ==和equals以及hashcode
    【线程分析】
    【dubbo&zookeeper】
    线程安全实现方案
    IOC原理
    java锁
    java特殊运算符
    HashMap原理和TreeMap原理
    volatile与synchronized
  • 原文地址:https://www.cnblogs.com/yuananyun/p/3523772.html
Copyright © 2020-2023  润新知