如何监听WPF的WebBrowser控件弹出新窗口的事件

 我来答
huanglenzhi
推荐于2016-06-17 · 知道合伙人数码行家
huanglenzhi
知道合伙人数码行家
采纳数:117538 获赞数:517199
长期从事计算机组装,维护,网络组建及管理。对计算机硬件、操作系统安装、典型网络设备具有详细认知。

向TA提问 私信TA
展开全部
  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>, UnsafeNativeMethods.DWebBrowserEvents2
  {
  ......
  }
  仍然是一个WebBrowserEvent!悲剧的是,这个WPF的WebBrowserEvent,并没有触发NewWindowEvent:
  

  public void NewWindow2(ref object ppDisp, ref bool cancel)
  {
  }
  现在知道为什么WPF的WB控件没有NewWindow事件了吧?微软的童鞋压根儿就没写!
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式