2010-10-04 87 views
5

見下面的程序。 我用功能abc開始一個新的線程x,然後我做一些更長的任務。 爲什麼x只在end sub之後開始?它不應該馬上開始睡覺嗎?爲什麼我的線程不能立即啓動?

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 
     Dim x As New Threading.Thread(AddressOf abc) 
     x.SetApartmentState(Threading.ApartmentState.MTA) 
     x.Start() 

     System.Threading.Thread.Sleep(5000) 
    End Sub 





Sub abc() 
    For i As Integer = 0 To 10 Step 1 
     Me.lblStatus.Text = "Testing DB connection (timeout in: " + i.ToString() + "s)" 
     'Me.StatusStrip1.Invoke(
     MsgBox(i.ToString) 
     System.Threading.Thread.Sleep(1000) 
    Next 
End Sub 



編輯:
解決的辦法是這樣的:

(A)將兩個連接嘗試和超時倒計時到單獨的線程。
(B)更新這樣的UI:

If Me.InvokeRequired Then 
     Me.Invoke(pUpdateStatusMessage, "Successfully connected.") 
    Else 
     UpdateStatusMessage("Successfully connected.") 
    End If 

有了這個全局聲明,所以沒有參數傳遞是必要的:

Delegate Sub t_pUpdateStatusText(ByVal strMessage As String) 
Public pUpdateStatusMessage As t_pUpdateStatusText = New t_pUpdateStatusText(AddressOf UpdateStatusMessage) 

Public Sub UpdateStatusMessage(ByVal strMessage As String) 
    Me.lblStatus.Text = strMessage 
    Me.StatusStrip1.Update() 
End Sub 
+0

你如何驗證線程只在方法結束後才啓動?你在看標籤嗎?還是你在等待一個斷點? – 2010-10-04 16:05:35

+0

實際上,當它沒有顯示時,我設置了一個斷點。 – 2010-10-05 06:52:00

回答

10

abc函數確實會在Button1_Click方法結束之前開始。是什麼造成的混亂是2件事

第一個是你直接更新從後臺線程的UI具有以下行

Me.lblStatus.Text = "Testing DB connection (timeout in: " + i.ToString() + "s)" 

這個代碼不正確,可以在以後導致問題。您必須使用Invoke調用才能真正更改UI。正如你在第二行中所做的那樣,這會讓我們接觸到下一個問題。

Invoke呼叫是同步的。它基本上將消息推送到Windows消息隊列中並等待它在返回之前進行處理。主線程中添加的Thread.Sleep調用會阻止消息隊列實際運行。這有效地阻止了後臺線程,直到Sleep調用完成,從而顯示後臺線程未運行。

2

你從非更新UI UI線程。這是不允許的,並可能導致奇怪的行爲。我不知道這是什麼原因導致你的延遲行爲,但你需要首先解決。

0

要添加到別人的話,你可以創建一個委託來定義你的控件更新需求的簽名(在這種情況下,我假設文本框和字符串,但可以定義,但你需要),和然後創建一個跟隨該委託簽名的方法,如果需要,它可以異步遞歸調用它自己。

事情是這樣的:

private delegate void ControlUpdateTextHandler(TextBox ctrl, string text); 
public void UpdateControlText(TextBox ctrl, string text) 
{ 
    if (ctrl.InvokeRequired) 
    { 
     ctrl.BeginInvoke((ControlUpdateTextHandler)UpdateControlText, ctrl, text); 
    } 
    else 
     ctrl.Text = text; 
} 

應該工作,如果它是從「正確的」線程調用(因爲InvokeRequired將是錯誤的,如果這是由擁有控制線程調用)通過簡單地更新文本,或從「不正確的」線程(因爲InvokeRequired在從不同的線程調用時將爲true),通過排隊由UI線程執行的調用。

0

也許與您的問題無關,但爲了從單獨的線程更新UI,我建議您使用BackgroundWorker。在DoWork中放置abc()函數,並使用ProgessChanged更新UI。

相關問題