<=======================
做者: 譚劍
關鍵字:C#,.NET,WebBrowser,ExtendedWebBrowser,瀏覽器,徹底載入,新窗口,腳本
=======================>
.NET 2.0 提供了一個新的WebBrowser控件.該WebBrowser控件爲咱們帶來了許多很是實用的新特性.舉個簡單的例子:
HtmlDocument htmlDoc = webBrowser.Document;
HtmlElement btnElement = htmlDoc.All["btnClose"];
if (btnElement != null)
{
btnElement.click += new HtmlElementEventHandler(HtmlBtnClose_Click);
}
僅需相似這樣簡單易懂的幾行代碼,即可實現Windows Forms對Web頁面各個HTML元素各類事件的響應.
在Windows Forms與Web頁面交互這方面,在功能與易用性上,該WebBrowser控件達到了一個史無前例的高度.這樣的特性,就已經爲咱們在進行相關的Windows Forms程序開發時選用它提供了足夠的理由.
很顯然,WebBrowser控件是對SHDocVw的AxWebBrowser這個非託管的ActiveX控件進行了封裝.可是在實用中,咱們很快能夠發現,其在提供新特性的同時,並無所有暴露出AxWebBrowser原有的屬性和方法,在不少狀況下,這樣就使得它顯得有點捉襟見肘了.
jlandheer對這個WebBrowser控件進行了擴展(
見Extended .NET 2.0 WebBrowser Control).可是該ExtendedWebBrowser也僅僅是提供了一個結構和思路,真正實現的擴展也比較有限.
根據實際的須要,我又對ExtendedWebBrowser進行了再擴展.
判斷頁面是否徹底載入:
1.新增DocumentCompleted事件:
在類ExtendedWebBrowser裏面事件部分的末尾添加以下代碼:
public new event EventHandler<BrowserExtendedNavigatingEventArgs> DocumentCompleted;
protected void OnDocumentCompleted(BrowserExtendedNavigatingEventArgs e)
{
if (e == null)
throw new ArgumentNullException("e");
if (this.DocumentCompleted != null)
this.DocumentCompleted(this, e);
}
2.實現public void DocumentComplete(object pDisp, ref object URL)方法:
在文件ExtendedWebBrowser.cs class WebBrowserExtendedEvents : UnsafeNativeMethods.DWebBrowserEvents2 的 Unused events區域裏面能夠找到未實現的方法:
public void DocumentComplete(object pDisp, ref object URL)
{
}
將其剪貼到已實現的方法部分的末尾,並修改成:
public void DocumentComplete(object pDisp, ref object URL)
{
BrowserExtendedNavigatingEventArgs args = new BrowserExtendedNavigatingEventArgs(pDisp, new Uri(URL.ToString()), null, UrlContext.None);
_Browser.OnDocumentCompleted(args);
}
3.修改原有DocumentCompleted事件的響應:
因爲上面重寫了DocumentCompleted事件,因此須要修改原有的DocumentCompleted事件響應:
修改類BrowserControl中
_browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(_browser_DocumentCompleted);
爲:
_browser.DocumentCompleted += new EventHandler<BrowserExtendedNavigatingEventArgs>(_browser_DocumentCompleted);
修改
void _browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
爲:
void _browser_DocumentCompleted(object sender, BrowserExtendedNavigatingEventArgs e)
其它相應的地方進行一樣的修改.
4.發送DocumentCompleted事件到最外層:
該ExtendedWebBrowser演示程序經過類WindowManager管理了一個標籤瀏覽器,若是須要,咱們能夠將事件發送到最外層,提供給MainForm使用.
將WindowManager中的代碼
void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
CheckCommandState();
}
改爲:
void WebBrowser_DocumentCompleted(object sender, BrowserExtendedNavigatingEventArgs e)
{
OnDocumentCompleted(sender, e);
CheckCommandState();
}
public event EventHandler<BrowserExtendedNavigatingEventArgs> DocumentCompleted;
/// <summary>
/// Raises the DocumentCompleted event
/// </summary>
/// <param name="e"></param>
protected virtual void OnDocumentCompleted(object sender, BrowserExtendedNavigatingEventArgs e)
{
if (DocumentCompleted != null)
DocumentCompleted(sender, e);
}
5.在須要的地方響應DocumentCompleted事件:
如:
_windowManager.DocumentCompleted += new EventHandler<BrowserExtendedNavigatingEventArgs>(_windowManager_DocumentCompleted);
.
.
.
void _windowManager_DocumentCompleted(object sender, BrowserExtendedNavigatingEventArgs e)
{
// 頁面徹底載入
if (e.AutomationObject == ((ExtendedWebBrowser)sender).Application)
{
MessageBox.Show("DocumentCompleted:" + e.Url.ToString());
}
}
注意:必須e.AutomationObject == ((ExtendedWebBrowser)sender).Application才說明頁面已經徹底載入.因爲Web頁面可能爲多個框架嵌套的(可能還有其它的狀況,還沒有深究),那麼載入過程當中對應會有多個DocumentCompleted事件,而只有頁面徹底載入了,纔會e.AutomationObject == ((ExtendedWebBrowser)sender).Application.這就是爲何要費盡千辛萬苦把pDisp傳遞出來的緣由.
不彈出頁面,仍在當前瀏覽器瀏覽:
ExtendedWebBrowser中的StartNewWindow事件在彈出新頁面的時候觸發.其擴展的事件數據BrowserExtendedNavigatingEventArgs中已經提供了上下文,新頁面的URL,ppDisp等所需的數據.因此咱們只需改動類BrowserControl中的方法
void _browser_StartNewWindow(object sender, BrowserExtendedNavigatingEventArgs e)
爲:
void _browser_StartNewWindow(object sender, BrowserExtendedNavigatingEventArgs e)
{
// Here we do the pop-up blocker work
// 這些彈出窗口過濾的代碼若是不須要,就所有刪除掉
if (allowPopup)
{
// Check wheter it's a HTML dialog box. If so, allow the popup but do not open a new tab
if (!((e.NavigationContext & UrlContext.HtmlDialog) == UrlContext.HtmlDialog))
{
ExtendedWebBrowser ewb = mf.WindowManager.New(false);
// The (in)famous application object
e.AutomationObject = ewb.Application;
}
}
//在這裏使用: e.AutomationObject = _browser.Application;彷佛沒有做用,
//可是他原來的代碼e.AutomationObject = ewb.Application;是有用的(見上面註釋)
//不知道是什麼緣由,只好暫時採用這個辦法
_browser.Navigate(e.Url);
e.Cancel = true;
}
這裏若是使用e.AutomationObject = _browser.Application的話,彷佛同他原來的代碼e.AutomationObject = ewb.Application惟一的區別就是一個browser是瀏覽過頁面了的,一個browser.是新建的,難道會同這個有關?
哪位若是知道緣由,還請不吝賜教!
不彈出腳本錯誤提示框:
ExtendedWebBrowser經過響應事件WebBrowser.Document.Window.Error來捕獲腳本錯誤提示框彈出的消息:
void _browser_DownloadComplete(object sender, EventArgs e)
{
// Check wheter the document is available (it should be)
if (this.WebBrowser.Document != null)
{
// Subscribe to the Error event
this.WebBrowser.Document.Window.Error += new HtmlElementErrorEventHandler(Window_Error);
.
.
.
void Window_Error(object sender, HtmlElementErrorEventArgs e)
{
// We got a script error, record it
ScriptErrorManager.Instance.RegisterScriptError(e.Url, e.Description, e.LineNumber);
// Let the browser know we handled this error.
e.Handled = true;
}
可是彷佛仍是因爲前面提到的Web頁面存在多個框架嵌套的緣由,其可以捕獲到的消息比較有限,有很大一部分腳本錯誤提示消息仍然會捕獲不到.這樣一個問題困擾了我幾天.後來忽然發現ExtendedWebBrowser裏面有以下的代碼:
/// <summary>
/// This method supports the .NET Framework infrastructure and is not intended to be used directly from your code.
/// Called by the control when the underlying ActiveX control is created.
/// </summary>
/// <param name="nativeActiveXObject"></param>
[PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
protected override void AttachInterfaces(object nativeActiveXObject)
{
this.axIWebBrowser2 = (UnsafeNativeMethods.IWebBrowser2)nativeActiveXObject;
base.AttachInterfaces(nativeActiveXObject);
}
原來AxWebBrowser在這裏!因而簡單的設置了axIWebBrowser2.Silent屬性:
protected override void AttachInterfaces(object nativeActiveXObject)
{
this.axIWebBrowser2 = (UnsafeNativeMethods.IWebBrowser2)nativeActiveXObject;
this.axIWebBrowser2.Silent = true;//不彈腳本錯誤框
base.AttachInterfaces(nativeActiveXObject);
}
再也不彈出任何提示框,Silent屬性真的是恰如其名,整個世界清靜了...*^_^*
從上面的內容能夠看出,ExtendedWebBrowser截取了AxWebBrowser接口.那麼,不難想象,雖然個人"再擴展"只擴展瞭如上三項功能,其實咱們如今能夠作咱們任何想作的!
<=======================
做者: 譚劍