一年多以前,写过这么一篇文章:基于IE内核的浏览器:WebBrowser上的网页与Winform本身交互[Demo下载],其中演示了WebBrowser与其宿主Winform之间的交互,实现在WebBrowser的C/S程序中调用其网页上的Javascript函数,甚至反过来在网页的Javascript代码中调用C/S程序中的方法。
而最近在开发 CorePlex 的过程中,却无意发现,原来 WebBrowser 本身就有一个用于交互操作的成员:
MSDN上这样说:
使用该属性启用 WebBrowser 控件承载的网页与包含 WebBrowser 控件的应用程序之间的通信。使用该属性可以将动态 HTML (DHTML) 代码与客户端应用程序代码集成在一起。为该属性指定的对象可作为 window.external 对象(用于主机访问的内置 DOM 对象)用于网页脚本。
可以将此属性设置为希望其公共属性和方法可用于脚本代码的任何 COM 可见的对象。可以通过使用 ComVisibleAttribute 对类进行标记使其成为 COM 可见的类。
若要从客户端应用程序代码调用网页中定义的函数,请使用可从 Document 属性检索的 HtmlDocument 对象的 HtmlDocument..::.InvokeScript 方法。
既然如此,上一篇文章中“B/S调用C/S方法”一节,就显得太山寨了。而正确的使用方式,应该这样:
1. 设置宿主Form 为 Com可见:
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public partial class MainForm : Form
2. 将窗体的引用赋值给 WebBrowser.ObjectForScripting 属性
this.webBrowser1.ObjectForScripting = this;
至此,我们就可以在网页上,使用 window.external 来访问 MainForm 这个窗体实例了:
<script language="JavaScript" type="text/javascript"> var f = window.external; function show() { // 窗体实例及其属性 alert(f + "\n\n" + f.Text); } function set() { // 调用窗体实例的 Public 方法 f.SetText("从网页设置的新标题"); } function addfav() { window.external.addFavorite('http://www.udnz.com', 'CorePlex代码库'); } </script> <input type="button" onclick="javascript:show();" value='窗体实例及其属性' /><br /> <br /> <input type="button" onclick="javascript:set();" value='f.SetText("从网页设置的新标题");' /><br /> <br /> 由于 window.external 的改变,原本在IE中可以执行的代码, 现在不能了,比如常用的加入收藏的代码:<br /> <input type="button" onclick="javascript:addfav();" value='加入收藏' />
有了这个能力,现在你就可以发挥你的想象,让浏览器中一个简单的超链接,变身为超人,执行对 Winform 的强大操作了!不过请注意,由于你重新给 window.external 赋值了,因此通过这个成员调用的任何属性、方法,都应当是你 MainForm 中的东西,所以原来可以通过 window.external 调用的东西,就不再能调用了。