【WPF】监听WPF的WebBrowser控件弹出新窗口的事件
原文:【WPF】监听WPF的WebBrowser控件弹出新窗口的事件
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方法中有这么一段:
代码
{
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类型的定义。
代码
public interface DWebBrowserEvents2
{
......
}
实际上,我们再去看WebBrowserEvent的定义,它恰恰是实现了这个接口的。
[ClassInterface(ClassInterfaceType.None)]private class WebBrowserEvent : StandardOleMarshalObject, UnsafeNativeMethods.DWebBrowserEvents2{ ......}
因此,上面这句话不难理解,就是定义一个实现了特定COM接口的类型,让浏览器控件的事件能够转发到这个类型实例去处理。因此,NewWindow2其实是浏览器控件去调用的。
Winform的WebBrowser我们搞清楚了,下面我们来看WPF的。其实,打开WPF的WebBrowser代码之后,我们会发现它跟Winform的WebBrowser机制是一样的。一个似曾相识的CreateSink方法映入眼中:
代码
internal override void CreateSink()
{
this._cookie = new ConnectionPointCookie(this._axIWebBrowser2, this._hostingAdaptor.CreateEventSink(), typeof(UnsafeNativeMethods.DWebBrowserEvents2));
}
这儿也有一个ConnectionPointCookie,但是它的访问权限是internal的:(
第二个参数,_hostingAdapter.CreateEventSink返回的是什么呢:
代码
internal virtual object CreateEventSink()
{
return new WebBrowserEvent(this._webBrowser);
}
[ClassInterface(ClassInterfaceType.None)]
internal class WebBrowserEvent : InternalDispatchObject<UnsafeNativeMethods.DWebBrowserEvents2>, UnsafeNativeMethods.DWebBrowserEvents2
{
......
}
仍然是一个WebBrowserEvent!悲剧的是,这个WPF的WebBrowserEvent,并没有触发NewWindowEvent:
public void NewWindow2(ref object ppDisp, ref bool cancel){}
现在知道为什么WPF的WB控件没有NewWindow事件了吧?微软的童鞋压根儿就没写!
既然微软的童鞋不写,那我们就自己折腾一把,反正原理已经搞清楚了。
首先,我们也得定义一个DWebBrowserEvents2接口,这个我们直接通过Reflector复制一份就好了。代码就不贴上来了。
接着,我们再仿造一个WebBrowserEvent,关键是要触发NewWindow事件:
代码
{
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的呢):
代码
{
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中打开:
【示例代码】
(新建按钮点击后,请输入完整的网址,例如:http://www.sina.com)
【WPF】监听WPF的WebBrowser控件弹出新窗口的事件的更多相关文章
- WPF中禁止WebBrowser控件打开新窗口
一.针对纯WPF的WebBrowser控件: <summary> Suppress Script Errors In WPF WebBrowser </summary> pub ...
- WPF中不规则窗体与WebBrowser控件的兼容问题解决办法
原文:WPF中不规则窗体与WebBrowser控件的兼容问题解决办法 引言 这几天受委托开发一个网络电视项目,要求初步先使用内嵌网页形式实现视频播放和选单,以后再考虑将网页中的所有功能整合进桌面程序. ...
- VC-基础-WebBrowser控件中弹出新网页窗口
用webbrowser控件浏览网页时,常弹出新的网页窗口,若不做任何控制的话,会在默认浏览器(一般是IE)中打开,这样就在新的窗口打开了,原程序就很难控制了,且存在webbrowser控件和IE的se ...
- Android监听Button和ImageButton控件的点击事件
一.onClick事件 Button和ImageButton都有一个onClick事件,通过自身的.setOnClickListener(OnClickListener)方法添加点击事件 所有的控件都 ...
- VC6.0 MFC中WebBrowser控件禁止新窗口弹出的解决办法
http://blog.csdn.net/gnorth/article/details/7258293 分类: WebBrowser MFC 禁止新窗口2012-02-14 15:25 1787人阅读 ...
- C#调用webbrowser,阻止弹出新HTML页面
参考资料: 1.C#调用webbrowser,阻止弹出新IE窗口 http://www.cnblogs.com/blindman/p/3819649.html 2.[WPF]监听WPF的WebBrow ...
- WPF中不规则窗体与WindowsFormsHost控件的兼容问题完美解决方案
首先先得瑟一下,有关WPF中不规则窗体与WindowsFormsHost控件不兼容的问题,网上给出的解决方案不能满足所有的情况,是有特定条件的,比如 WPF中不规则窗体与WebBrowser控件的兼 ...
- Webbrowser控件判断网页加载完毕的简单方法 (转)
摘自:http://blog.csdn.net/cometnet/article/details/5261192 一般情况下,当ReadyState属性变成READYSTATE_COMPLETE时,W ...
- 屏蔽webbrowser控件右键的一种方法
原文:屏蔽webbrowser控件右键的一种方法 Option ExplicitPrivate Declare Sub ZeroMemory Lib "KERNEL32" Alia ...
随机推荐
- java生产者消费者问题代码分析
作者要的是一个生产者生成,接着必须有一个消费者消费,那这不是需要单线程吗?或者使用1个大小的阻塞队列.所以只谈论问题本身,不谈论好不好. 具体代码: import java.util.concurre ...
- Qt学习之路(54): 自定义拖放数据对象
前面的例子都是使用的系统提供的拖放对象 QMimeData 进行拖放数据的存储,比如使用 QMimeData::setText() 创建文本,使用 QMimeData::urls() 创建 URL 对 ...
- UTL_RAW
The UTL_RAW package provides SQL functions for manipulating RAW data types. 该包的功能其实可以用来加密: SELECT ...
- linux查看接口连接状态
ethtool # ethtool em1 Settings for em1: Supported ports: [ TP ] Supported link modes: 10baseT/Half 1 ...
- 泛虚拟化技术(以Xen为例)
一.概述 最主要的特点是:修改Guest OS的内核代码.通过修改内核,使Guest OS明白自己是运行在R-1,不要直接去运行特权指令,如果要运行就去Hypercall(主动VMM陷入). ...
- UVA 1524 - Hot or Cold?(数学)
UVA 1524 - Hot or Cold? 题目链接 题意:给一个一元n次方程,带入x表示时间,f(x)表示温度,如今要求[s, e]的平均温度 思路:平均温度就是 总温度/ (e - s),画出 ...
- Android中Drawable分类汇总(上)
Android把可绘制的对象抽象为Drawable,不同的图形图像资源就代表着不同的drawable类型.Android FrameWork提供了一些具体的Drawable实现,通常在代码中都不会直接 ...
- Eclipse 优化方法(经典收藏)
第一步: 取消自动validationvalidation有一堆,什么xml.jsp.jsf.js等等,我们没有必要全部都去自动校验一下,只是需要的时候才会手工校验一下! 取消方法:windows–& ...
- BZOJ 3357: [Usaco2004]等差数列( dp )
dp(x, p) 表示序列中第x个数, 上一个数是p构成的等差数列的最长. 转移时从[1, x)中枚举p = seq[] 就行了.时间复杂度O(n²logn) -------------------- ...
- Spring注入静态变量(转)
今天碰到一个问题,我的一个工具类提供了几种静态方法,静态方法需要另外一个类的实例提供处理,因此就写出了这样的代码: Class Util{ private static XXX xxx; xxx = ...