谨慎注意WebBrowser控件的DocumentCompleted事件
?
引言
WebBrowser控件的DocumentCompleted事件一般就被認定為是在頁面完全加載完畢后產生,而注釋中也是這么寫的:
但事實卻并非如此。
首先它不一定會在完全加載完畢時才觸發,有時就會在加載過程中就會觸發。
其次按照“完全加載完畢后”來理解,會認為通常一次頁面跳轉只會引發一次該事件,事實也并非如此,某些頁面加載時會引發十多次乃至更多。
試驗
做一個簡單試驗,首先設計這樣的界面:
然后為那個轉到按鈕添加單擊事件處理:
private?void?button1_Click(object?sender,?EventArgs?e)
{
????webBrowser1.Navigate(textBox1.Text);
}
再為WebBrowser控件的DocumentCompleted事件添加處理:
private?void?webBrowser1_DocumentCompleted(object?sender,?WebBrowserDocumentCompletedEventArgs?e)
{
????listBox1.Items.Insert(0, webBrowser1.ReadyState);
}
在這里就是輸出WebBrowser控件的ReadyState屬性到列表中。
運行并測試:
可以看到加載某些頁面時會引發很多次該事件,并且狀態都是一連串的Interactive。
究其原因是與頁面復雜度有關的,猜想是因iFrame或Ajax加載完畢而觸發的。
而觸發DocumentCompleted事件時ReadyState為Complete的情況通常只在每次加載頁面時出現一次,所以這時我們才應認為其已完全加載。但也并非一個頁面100%只會出現一次這種情況,比如頁面中Google的“更多”鏈接點擊后僅僅是彈出一個列表,但這時又會出現一次Complete。
這會導致什么問題?
假如在ReadyState為Interactive甚至是Loading時對頁面實施操控,那很可能無效或引發異常。
而假如忽視這種一頁多發事件的情況,會導致大量重復操作,從而引發異常或邏輯問題。
該如何解決?
以下代碼可以確保你不會在未加載完畢時執行操作:
private?void?webBrowser1_DocumentCompleted(object?sender,?WebBrowserDocumentCompletedEventArgs?e)
{
????if?(webBrowser1.ReadyState?<?WebBrowserReadyState.Complete)?return;
????//執行正常流程代碼…………
}
如果需要嚴格控制每頁只能執行一次代碼,那么需要附加一個屬性或變量來記錄上次訪問的網址,并據此進行判斷:
private?void?webBrowser1_DocumentCompleted(object?sender,?WebBrowserDocumentCompletedEventArgs?e)
{
????if?(webBrowser1.ReadyState?<?WebBrowserReadyState.Complete?||?webBrowser1.Url.ToString()?==?LastUrl)?return;
????LastUrl?=?webBrowser1.Url.ToString();
????//執行正常流程代碼…………
}
public?string?LastUrl
{
????get
????{
????????return?_LastUrl;
????}
????set
????{
????????_LastUrl?=?value;
????}
}
private?string?_LastUrl;
結語
WebBrowser是非常實用的控件,但也可說是粗制濫造的典范,各種問題層出不窮,從注釋對不上實際功能這一點來看,就知道開發者多么漫不經心了。還有就是ReadyState屬性其實是一個非常關鍵的屬性,而開發者卻沒有設置一個事件來監控其狀態變更,真是太失敗了。
總結
以上是生活随笔為你收集整理的谨慎注意WebBrowser控件的DocumentCompleted事件的全部內容,希望文章能夠幫你解決所遇到的問題。