2014-12-26 回答

wpf中自带一个webbrowser控件,当我们使用它打开一个网页,例如百度,然后点击它其中的链接时,如果这个链接是会弹出一个新窗口的,那么它会生生的弹出一个ie窗口来,而不是在内部跳到该链接。

如果使用winform的webbrowser控件,我们可以监听它的newwindow事件,在这个事件中做一些处理,例如,在新建一个tab来打开,或者控制它在当前webbrowser中跳转。很不幸的是,wpf的webbrowser没有这个事件。

说到底,winform的wb或者是wpf的wb都是在调用ie的一个控件,因此,winform能加上的,我们wpf一定也有办法加上。如此,那我们就请出神器reflector,研究一把。

首先,我们打开winform的webbrowser,找到触发newwindow事件的代码:

protected virtual void onnewwindow(canceleventargs e)

{

if (this.newwindow != null)

{

this.newwindow(this, e);

}

}

它是在onnewwindow方法中触发的。那么,是谁调用了这个onnewwindow呢?接着搜索,最后在一个叫webbrowserevent的类里面发现这么一段:

public void newwindow2(ref object ppdisp, ref bool cancel)

{

canceleventargs e = new canceleventargs();

this.parent.onnewwindow(e);

cancel = e.cancel;

}

我们接着搜newwindow2,却发现没有地方显式地调用它了。既然从方法入手没找到,那我们就来研究一下定义这个方法的webbrowserevent,看看是谁在使用它。

仔细搜索一遍,最后发现在webbrowser的createsink方法中有这么一段:

代码

protected override void createsink()

{

object activexinstance = base.activexinstance;

if (activexinstance != null)

{

this.webbrowserevent = new webbrowserevent(this);

this.webbrowserevent.allownavigation = this.allownavigation;

this.cookie = new axhost.connectionpointcookie(activexinstance, this.webbrowserevent, typeof(unsafenativemethods.dwebbrowserevents2));

}

}

注意这句话:

this.cookie = new axhost.connectionpointcookie(activexinstance, this.webbrowserevent, typeof(unsafenativemethods.dwebbrowserevents2));

很显然,这句话是关键。axhost.connectionpointcookie类的作用是:“将一个activex 控件连接到处理该控件的事件的客户端”。

上面的调用中有一个很奇怪的类型:dwebbrowserevents2,熟悉com的童鞋应该马上能想到,这其实是一个com类型的定义。

代码

[comimport, typelibtype(typelibtypeflags.fhidden), interfacetype(cominterfacetype.interfaceisidispatch), guid("34a715a0-6587-11d0-924a-0020afc7ac4d")]

public interface dwebbrowserevents2

{

......

}

实际上,我们再去看webbrowserevent的定义,它恰恰是实现了这个接口的。

[classinterface(classinterfacetype.none)]

private class webbrowserevent : standardolemarshalobject, unsafenativemethods.dwebbrowserevents2

{

......

}

因此,上面这句话不难理解,就是定义一个实现了特定com接口的类型,让浏览器控件的事件能够转发到这个类型实例去处理。因此,newwindow2其实是浏览器控件去调用的。

winform的webbrowser我们搞清楚了,下面我们来看wpf的。其实,打开wpf的webbrowser代码之后,我们会发现它跟winform的webbrowser机制是一样的。一个似曾相识的createsink方法映入眼中:

代码

[securitytreatassafe, securitycritical]

internal override void createsink()

{

this._cookie = new connectionpointcookie(this._axiwebbrowser2, this._hostingadaptor.createeventsink(), typeof(unsafenativemethods.dwebbrowserevents2));

}

这儿也有一个connectionpointcookie,但是它的访问权限是internal的:(

第二个参数,_hostingadapter.createeventsink返回的是什么呢:

代码

[securitycritical]

internal virtual object createeventsink()

{

return new webbrowserevent(this._webbrowser);

}

[classinterface(classinterfacetype.none)]

internal class webbrowserevent : internaldispatchobject, unsafenativemethods.dwebbrowserevents2

{

......

}

仍然是一个webbrowserevent!悲剧的是,这个wpf的webbrowserevent,并没有触发newwindowevent:

public void newwindow2(ref object ppdisp, ref bool cancel)

{

}

现在知道为什么wpf的wb控件没有newwindow事件了吧?微软的童鞋压根儿就没写!

既然微软的童鞋不写,那我们就自己折腾一把,反正原理已经搞清楚了。

首先,我们也得定义一个dwebbrowserevents2接口,这个我们直接通过reflector复制一份就好了。代码就不贴上来了。

接着,我们再仿造一个webbrowserevent,关键是要触发newwindow事件:

代码

public partial class webbrowserhelper

{

private class webbrowserevent : standardolemarshalobject, dwebbrowserevents2

{

private webbrowserhelper _helperinstance = null;

public webbrowserevent(webbrowserhelper helperinstance)

{

_helperinstance = helperinstance;

}

......

public void newwindow2(ref object pdisp, ref bool cancel)

{

_helperinstance.onnewwindow(ref cancel);

}

......

}

}

最后,我们需要仿造framework中的代码,也来createsink一把(我承认,用了反射来取webbrowser内部的东东,谁让这些类型都是internal的呢):

代码

private void attach()

{

var axiwebbrowser2 = _webbrowser.reflectgetproperty("axiwebbrowser2");

var webbrowserevent = new webbrowserevent(this);

var cookietype = typeof(webbrowser).assembly.gettype("ms.internal.controls.connectionpointcookie");

_cookie = activator.createinstance(

cookietype,

reflectionservice.bindingflags,

null,

new[] { axiwebbrowser2, webbrowserevent, typeof(dwebbrowserevents2) },

cultureinfo.currentuiculture);

}

最后的使用:

var webbrowserhelper = new webbrowserhelper(webbrowser);

......

webbrowserhelper.newwindow += webbrowseronnewwindow;

【效果图】

初始网页:

点击一个链接,默认情况下,将是弹出一个ie窗口,现在是在新的tab中打开:

wpf 监听退出事件_如何监听WPF的WebBrowser控件弹出新窗口的事件相关推荐

  1. 【WPF】监听WPF的WebBrowser控件弹出新窗口的事件

    WPF中自带一个WebBrowser控件,当我们使用它打开一个网页,例如百度,然后点击它其中的链接时,如果这个链接是会弹出一个新窗口的,那么它会生生的弹出一个IE窗口来,而不是在内部跳到该链接. 如果 ...

  2. Android 点击事件,如何在界面上或者某个控件上添加点击事件

    说到点击事件,第一印象 setOnClickListener() 方法,这也是用的最多的控件点击事件方法,这篇文章不分享这个方法,使用该方法的前提是你要拿到这个控件的 View 才可以调用这个方法 通 ...

  3. vb检测html事件,VB代码VB小程序:捕获 WebBrowser 控件的鼠标事件

    49. 捕获 WebBrowser 控件的鼠标事件 VB 的网页浏览控件 WebBrowser 没有 MouseDown.MouseMove.MouseUp 等鼠标事件,要在程序中捕获这些事件,必须另 ...

  4. pb调用计算机默认游览器,PB打开ole控件IE浏览器版本问题_指定Webbrowser控件所用IE内核版本(转)...

    如果电脑上安装了IE8或者之后版本的IE浏览器,Webbrowser控件会使用IE7兼容模式来显示网页内容.解决方法是在注册表中为你的进程指定引用IE的版本号. 比如我的程序叫做a.exe 对于32位 ...

  5. WebBrowser控件的常用方法、属性和事件

    1. 属性 属性 说明 Application 如果该对象有效,则返回掌管WebBrowser控件的应用程序实现的自动化对象(IDispatch).如果在宿主对象中自动化对象无效,这个程序将返回Web ...

  6. 一个WinForm记事本程序(包含主/下拉/弹出菜单/打开文件/保存文件/打印/页面设置/字体/颜色对话框/剪切版操作等等控件用法以及记事本菜单事件/按键事件的具体代码)...

    (一).说明 功能类似Windows 操作系统自带的记事本.  一个WinForm记事本程序(包含主/下拉/弹出 菜单/打开保存对话框等控件用法以及记事本菜单事件的具体代码) (二).图片示例 (三) ...

  7. WPF 把图片分割成两份自动翻页 WpfFlipPageControl:CtrlBook 书控件

    原文:WPF 把图片分割成两份自动翻页 WpfFlipPageControl:CtrlBook 书控件 版权声明:本文为博主原创文章,需要转载尽管转载. https://blog.csdn.net/z ...

  8. ajax获取单选按钮的值_【自学C#】|| 笔记 31 控件,按钮

    一.Button:按钮控件 按钮主要用于提交页面的内容,或者是确认某种操作等.     按钮常用的属性包括在按钮中显示的文字 (Text) 以及按钮外观设置的属性,最常用的事件是单击事件. 1.例: ...

  9. 谨慎注意WebBrowser控件的DocumentCompleted事件

    引言 WebBrowser控件的DocumentCompleted事件一般就被认定为是在页面完全加载完毕后产生,而注释中也是这么写的: 但事实却并非如此. 首先它不一定会在完全加载完毕时才触发,有时就 ...

  10. 在WPF的WebBrowser控件中抑制脚本错误

    在WPF的WebBrowser控件中抑制脚本错误 原文:在WPF的WebBrowser控件中抑制脚本错误 今天用WPF的WebBrowser控件的时候,发现其竟然没有ScriptErrorsSuppr ...

最新文章

  1. 【网络流24题】D、魔术球问题(有向无环图的最小路径覆盖、思维)
  2. 张家界a货翡翠,酒泉a货翡翠
  3. mysql8 php7_windows10-nginx-mysql8.0-php7.0环境搭建
  4. 求二维数组中的最大值和最小值C语言,c语言 写一个子函数要求找出一个二维数组的最大值...
  5. AXMLPrinter2.jar反编译xml文件
  6. mongo connections url string 的问题
  7. AT5160-[AGC037C]Numbers on a Circle【贪心,堆】
  8. (转)Asp.net 中 Get和Post 的用法
  9. Mysql中Key与Index的区别
  10. Android P(2)---计划概览
  11. python基础7--socket
  12. mysql长连接_mysql.connector 数据库长连接
  13. python3关键字详解_Python解析、提取url关键字的实例详解
  14. android手机抓包工具 tcp协议,Android常用抓包工具之TcpDump
  15. 创建一个简单的ASP.NET Web应用程序
  16. WPS 表格中单元格文字后插入公式
  17. 10年软件测试工程师 常用八大测试用例设计方法
  18. 计算机安装win10系统还原,详细教您win10怎么还原成win7
  19. 在到达胜利之前无法回头
  20. 20135306-信息安全系统设计基础第一周学习总结

热门文章

  1. 利用Cookie进行自动登录
  2. 程序语言翻译: 2.1在以阶段划分的编译器中,贯穿于编译器工作始终的是( )。2.2 对高级语言程序进行翻译时,源程序中的变量不可能映射到( )
  3. 如何搭建经营分析看板
  4. 程序化交易学习笔记(六、模式、日内交易模型、Tick模型)
  5. 游戏命中判定:圆桌算法和程序实现
  6. RoaringBitmap数据结构以及精确去重UDAF实现
  7. 数据挖掘工具---Spark SQL使用
  8. windows10关闭java自动更新
  9. matlab在c盘有缓存文件夹吗,win10如何清除C盘缓存文件-win10清除C盘缓存的方法 - 河东软件园...
  10. Swift 声明(Declarations)