我正在尝试在我的某个应用中实现简单的网络浏览器控件。这是为了帮助将Web应用程序集成到我正在创建的工具集中。
问题是,这个网络应用程序绝对喜欢弹出窗口....
当弹出窗口打开时,它会在IE窗口中打开,该窗口不是我的主窗口所属的MDI容器窗体的子窗口。
如何通过单击我的WebBrowser中的链接创建任何和所有弹出窗口,使其成为我的MDI容器的子项(类似于设置表单的MDIParent属性)?
提前致谢。
答案 0 :(得分:25)
Web浏览器控件支持NewWindow事件以获得有关弹出窗口的通知。但Winforms包装器不会让你做太多,你只能取消弹出窗口。本机COM包装器允许传回Web浏览器的新实例,然后该实例将用于显示弹出窗口。
利用这一点需要一些工作。对于初学者,使用Project + Add Reference,Browse选项卡并选择c:\ windows \ system32 \ shdocvw.dll。这增加了对本机COM接口的引用。
创建一个充当弹出窗体的表单。删除WebBrowser并使其代码看起来类似于:
public partial class Form2 : Form {
public Form2() {
InitializeComponent();
}
public WebBrowser Browser {
get { return webBrowser1; }
}
}
浏览器属性允许访问将用于在弹出窗口中显示网页的浏览器。
现在回到主窗体。删除WebBrowser并使其代码如下所示:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
webBrowser1.Url = new Uri("http://google.com");
}
SHDocVw.WebBrowser nativeBrowser;
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
nativeBrowser = (SHDocVw.WebBrowser)webBrowser1.ActiveXInstance;
nativeBrowser.NewWindow2 += nativeBrowser_NewWindow2;
}
protected override void OnFormClosing(FormClosingEventArgs e) {
nativeBrowser.NewWindow2 -= nativeBrowser_NewWindow2;
base.OnFormClosing(e);
}
void nativeBrowser_NewWindow2(ref object ppDisp, ref bool Cancel) {
var popup = new Form2();
popup.Show(this);
ppDisp = popup.Browser.ActiveXInstance;
}
}
OnLoad方法获取对本机COM接口的引用,然后将事件处理程序订阅到NewWindow2事件。我确保在FormClosing事件处理程序中取消订阅该事件,而不是100%确定是否有必要。更好的安全然后抱歉。
NewWindow2事件处理程序是关键,请注意第一个参数允许传回一个无类型的引用。那应该是弹出窗口中的本机浏览器。所以我创建了一个Form2实例和Show()它。注意Show()的参数,它确保弹出窗口是一个拥有的窗口。根据您的应用需要替换它,我假设你想在你的情况下创建一个MDI子窗口。
请注意,当Javascript使用alert()时,此事件不会触发显示的窗口。浏览器不会将该窗口视为HTML弹出窗口,也不会使用浏览器窗口显示它,因此您无法拦截或替换它。
答案 1 :(得分:3)
我发现执行此操作的最佳方法是实现/接收NewWindow3 event
添加对 c:\ windows \ system32 \ shdocvw.dll 的引用,如其他答案中所述。
添加事件处理程序
SHDocVw.WebBrowser wbCOMmain = (SHDocVw.WebBrowser)webbrowser.ActiveXInstance;
wbCOMmain.NewWindow3 += wbCOMmain_NewWindow3;
事件方法
void wbCOMmain_NewWindow3(ref object ppDisp,
ref bool Cancel,
uint dwFlags,
string bstrUrlContext,
string bstrUrl)
{
// bstrUrl is the url being navigated to
Cancel = true; // stop the navigation
// Do whatever else you want to do with that URL
// open in the same browser or new browser, etc.
}
该帮助的来源MSDN Post
答案 2 :(得分:2)
精炼Hans回答,您可以派生WebBrowser来访问COM而无需添加引用。它是通过使用未发布的Winforms WebBrowser.AttachInterface和DetachInterface方法。
更详细here。
以下是代码:
用法(将WebBrowser实例更改为WebBrowserNewWindow2)
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.webBrowser1.NewWindow2 += webBrowser_NewWindow2;
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
webBrowser1.NewWindow2 -= webBrowser_NewWindow2;
base.OnFormClosing(e);
}
void webBrowser_NewWindow2(object sender, WebBrowserNewWindow2EventArgs e)
{
var popup = new Form1();
popup.Show(this);
e.PpDisp = popup.Browser.ActiveXInstance;
}
public WebBrowserNewWindow2 Browser
{
get { return webBrowser1; }
}
}
代码:
using System;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace SHDocVw
{
public delegate void WebBrowserNewWindow2EventHandler(object sender, WebBrowserNewWindow2EventArgs e);
public class WebBrowserNewWindow2EventArgs : EventArgs
{
public WebBrowserNewWindow2EventArgs(object ppDisp, bool cancel)
{
PpDisp = ppDisp;
Cancel = cancel;
}
public object PpDisp { get; set; }
public bool Cancel { get; set; }
}
public class WebBrowserNewWindow2 : WebBrowser
{
private AxHost.ConnectionPointCookie _cookie;
private WebBrowser2EventHelper _helper;
[PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
protected override void CreateSink()
{
base.CreateSink();
_helper = new WebBrowser2EventHelper(this);
_cookie = new AxHost.ConnectionPointCookie(
this.ActiveXInstance, _helper, typeof(DWebBrowserEvents2));
}
[PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
protected override void DetachSink()
{
if (_cookie != null)
{
_cookie.Disconnect();
_cookie = null;
}
base.DetachSink();
}
public event WebBrowserNewWindow2EventHandler NewWindow2;
private class WebBrowser2EventHelper : StandardOleMarshalObject, DWebBrowserEvents2
{
private readonly WebBrowserNewWindow2 _parent;
public WebBrowser2EventHelper(WebBrowserNewWindow2 parent)
{
_parent = parent;
}
public void NewWindow2(ref object pDisp, ref bool cancel)
{
WebBrowserNewWindow2EventArgs arg = new WebBrowserNewWindow2EventArgs(pDisp, cancel);
_parent.NewWindow2(this, arg);
if (pDisp != arg.PpDisp)
pDisp = arg.PpDisp;
if (cancel != arg.Cancel)
cancel = arg.Cancel;
}
}
[ComImport, Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch),
TypeLibType(TypeLibTypeFlags.FHidden)]
public interface DWebBrowserEvents2
{
[DispId(0xfb)]
void NewWindow2(
[In, Out, MarshalAs(UnmanagedType.IDispatch)] ref object ppDisp,
[In, Out] ref bool cancel);
}
}
}
答案 3 :(得分:0)
我知道这个问题已经很老了,但是我是这样解决的:添加新引用,在COM中选择Microsoft Internet Controls,然后在代码中,在打开新窗口的单击之前添加以下内容:
SHDocVw.WebBrowser_V1 axBrowser = (SHDocVw.WebBrowser_V1)webBrowser1.ActiveXInstance;
axBrowser.NewWindow += axBrowser_NewWindow;
,然后添加以下方法:
void axBrowser_NewWindow(string URL, int Flags, string TargetFrameName, ref object PostData, string Headers, ref bool Processed)
{
Processed = true;
webBrowser1.Navigate(URL);
}