緣起:上次寫了一個《WebBrowser控件的簡單應用2》,提到了在NewWindow事件中打開新窗口的例子。有網友“隊長 ”提出那個事件得到的參數是本頁面的,而不是新頁面的,經過測試,果然url參數不是新頁面的。
Open新頁面要處理的:
1:<<a href=’xxxxx’ target=’_blank’>>;
2: onclick=’window.open’ ;
3:引用js文件 ;
4:ClientScript.RegisterStartupScript();等。
5:還有要實現在打開的頁面里能用window.opener對象
Close要處理的:
1:onclick=’window.close ;
2:引用js文件 ;
3:ClientScript.RegisterStartupScript()等。
經過在網上搜索,結果並不令人滿意。基本上,WebBrowser控件不提供這個(將要打開的新頁面的地址)功能,只能通過其他方法。
這里介紹一下網上的一個簡單的解決方案、我的一個簡單方案、微軟的回答、一個終極解決方法。
網上現在有人給出這樣的一個解決方案:在_NewWindow事件通過wb_Container.StatusText來獲得當前將要打開的頁面。代碼可以這樣寫:
private void wb_Container_NewWindow(object sender, CancelEventArgs e)
{
e.Cancel = true;
string newURL = wb_Container.StatusText;
//'open
}
我測試了一下,這樣做基本上只能處理<a href=’xxxxx’ target=’_blank’>的這種情況。對於<button>里面的onlcick事件window.open()毫無作用。
原因很簡單,他只是利用了WebBrower現實Status的特點來做,不全面,不安全。至於其他情況也是完全不能處理,比如js中使用window.Open,這個方案根本不能檢查。
我的處理方法:
剛開始,我使用了這樣的思路:針對所有可能出現的情況,找個各個不同方法來處理。
比如說,對於<a herf=’’的這種情況,就用wb_Container.StatusText方法,但是要加入一個判斷。If(wb_Container.StatusText!=””)。對於window.open和RegisterStartupScript的,可以通過替換js來實現。
本來的window.open函數,在程序完成加載之后,我把這個函數修改成window.external.open,
然后,我把我的AppBrowser類里面加入幾個public的Open函數來對應原來的js的open函數就可以了。
這是一個代碼實現。
private void wb_Container_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
//for windows.open
if (wb_Container.DocumentText.IndexOf("window.open(") > -1 || wb_Container.DocumentText.IndexOf("window.close()") > -1)
{
wb_Container.DocumentText = wb_Container.DocumentText.Replace("window.open(", "window.external.open(").Replace("window.close()", "window.external.close()");
}
}
這樣處理之后,保證了我的瀏覽器也能理解這些js。
這個方案唯一不能處理的就是js文件里面有處理的情況。
還有一個小問題,替換之后的document對象的action變化了。這個可以通過方法來實現,就是替換上邊的函數,改用遞歸document.all來實現,檢查每個element控件的內容來實現。
但是,畢竟美中不足。
微軟的解釋是這樣的:這個問題,下一個版本在解決(http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=115195),開發者可以通過擴展WebBrower及其Event來實現。並且提供了一個簡單的代碼(但是顯示不完全)。是的,這是個好的解決方案,但不是我想要的。既然封裝了這個控件,為什么不提供這么重要的一個參數呢?
有高手已經做出了一個模型:(http://www.codeproject.com/csharp/ExtendedWebBrowser.asp)
(作者實現了一個類似IE7效果的瀏覽器)
這個模型里面,作者自己封裝並且擴展了這個控件,是個最終極的解決方法。
主要思路:提供了一個將要打開新窗口的事件,並且提供更多的參數。這些參數來自IWebBrowser2等接口,還提供了一些WndProc重載來實現window.close。
下載之后,我保留了這些類,做了一個簡單的測試
ExtendedWebBrowser : System.Windows.Forms.WebBrowser
.WebBrowserExtendedEvents : UnsafeNativeMethods.DWebBrowserEvents2
.WindowsMessages(enum)
UnsafeNativeMethods
.DWebBrowserEvents2([ComImport, TypeLibType((short)0x1010), InterfaceType((short)2), Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D")])
.IWebBrowser2([ComImport, SuppressUnmanagedCodeSecurity, TypeLibType(TypeLibTypeFlags.FOleAutomation | (TypeLibTypeFlags.FDual | TypeLibTypeFlags.FHidden)), Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E")])
BrowserExtendedNavigatingEventArgs : CancelEventArgs
UrlContext
ScriptError
NativeMethods
結果非常不錯。
主要處理的幾個地方:
NewWindow2和NewWindow3:處理新打開窗口
BeforeNavigate2:獲得將要打開的窗口的地址。
主要提供的新事件:_StartNewWindow(object sender, BrowserExtendedNavigatingEventArgs e)
下邊這一個是我的第二個AppBrowser類,使用上邊封裝擴展之后的WebBrower控件。
1 [System.Runtime.InteropServices.ComVisibleAttribute(true)]
2 public partial class AppBrowser2 : Form
3 {
4 property
19 cons.
41
42 window : close and open
55 other browser event
92
93 external function for js
114 }
