簡體   English   中英

使用Application.DoEvents()

[英]Using the Application.DoEvents()

我遇到了Application.DoEvents()可以解決的問題。 問題是WebBrowser假定非同步地導航到url,但是沒有,並且當我使用Application.DoEvents()時,它解決了這一問題,我認為這是因為應用程序處理了一些其他事件並且不傳遞事件。導航正常。

我了解了一些有關此方法的知識,並且了解該方法將導致應用程序處理所有當前事件。 現在我有點擔心,因為我用大炮殺死了一只螞蟻,有人可以告訴我我做的事情是否值得嗎?

是的,Application.DoEvents()解決了此問題。 核心問題是WebBrowser的核心是一個高線程組件。 您可以調用其Navigate()方法,它會在不阻塞代碼的情況下停止工作,該方法幾乎立即返回。

但是,問題在於它必須在某個時候運行DocumentCompleted事件。 保證可以在創建瀏覽器對象的線程上運行該線程。 很難做到,您的線程可能很忙於做其他事情。 就像坐在一個循環中一樣,測試ReadyState屬性。 沒有機制可以中斷此循環並運行事件處理程序。

因此,您看到的是ReadyState屬性從不更改,而DocumentCompleted事件從不觸發。 這稱為死鎖,這是線程代碼的一種非常常見的詛咒。 使用DoEvents是后門,“泵出消息循環”。 它允許瀏覽器進入您的線程並觸發事件。 依次更新ReadyState屬性並讓您跳出循環。

但是,DoEvents存在一個大問題。 它不是選擇性的,它不僅限於處理允許事件觸發的消息。 它還會分派其他通知,這種通知會使您的程序崩潰。 就像您的用戶對緩慢的網站不耐煩並關閉表格一樣。 那會破壞瀏覽器對象,但不會停止循環。 現在,您正在測試已處置瀏覽器的ReadyState屬性。 KABOOM!

您需要以不同的方式進行操作。 在循環中阻塞或掛斷UI線程永遠是不合法的,它很容易產生死鎖。 實際上,Microsoft准則禁止 STA線程使用它。 解決方法很簡單,將等待循環后現在擁有的所有代碼移至DocumentCompleted事件處理程序。 您可能需要向類中添加一些狀態變量,以使您知道該事件表示特定網頁的完成或用戶對結果不再感興趣。

Application.Dovents()方法處理所有待處理的消息。 這可能導致:

  1. 在當前代碼完成之前輸入兩次代碼塊。 (讓我們假設您通過單擊按鈕瀏覽瀏覽器。用戶單擊按鈕,而代碼正在等待瀏覽器再次提示用戶單擊。在這種情況下, Application.Doevents()將導致在執行下一行之前處理該方法。)

  2. 中斷關鍵代碼。 (假設您有一個耗時的方法,並且用戶單擊了關閉按鈕。您的表單將消失,但您的代碼將繼續運行。一個真正的問題。

  3. 更多意外結果。

但是我覺得有時使用此方法是必要的,並且是一個簡單的解決方案(例如webbrowser),很難在多線程中使用(尤其是在可見時)。 如果必須使用此方法,則應確保用戶和其他內容(計時器,按鈕,事件與)不會中斷任何內容。 有關詳細討論: Application.DoEvents()的使用

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM