2013-04-02 49 views
1

有一段時間了,我一直在使用此代碼:嘗試 - 多線程 - 在VB.net Windows窗體

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click 
    Dim t2 As New Threading.Thread(AddressOf SetLabelText2) 
    t2.IsBackground = True 
    t2.Start() 
End Sub 

Delegate Sub UpdateDelegate() 

Private Sub SetLabelText2() 
    If InvokeRequired Then 
     Invoke(New UpdateDelegate(AddressOf SetLabelText2)) 
    Else 
     For i = 1 To 110 
      Label2.Text = Text 
      Threading.Thread.Sleep(200) 
     Next 
    End If 
End Sub 

此代碼運行正常,但它不是我的多線程應用程序,並把它變成一個沒有反應州。

我的問題很簡單, 我1.How可以解決這個問題(我將使用將有幾個功能的應用程序調用內

If InvokeRequired Then 

    Invoke(New UpdateDelegate(AddressOf SetLabelText2)) 

Else 

    FunctionCall1() 

    FunctionCall2() 

    FunctionCall3() 

End If 

他們所有的工作,並採取抓住我的UI線程的。

我一直在尋找了一段時間,任何幫助表示讚賞。

CNC中 也有問題,而在一個線程從一種形式的幫助讀取信息... :)感謝到目前爲止

編輯---

好吧,我改變我的代碼到處尋找像

Delegate Sub setForm1PrgBarPerformStepdelegate(s As Integer) 
    Private Sub setForm1PrgBarPerformStep(ByVal s As Integer) 
     If Form1.ProgressBar1.InvokeRequired Then 
      Dim d As New setForm1lblAlltextdelegate(AddressOf setForm1PrgBarPerformStep) 
      Form1.Invoke(d, New Object() {s}) 
     Else 
      If s = 1 Then 
      Form1.ProgressBar1.PerformStep() 
     Else 

     End If 
    End If 
End Sub 

這段代碼被稱爲與setForm1PrgBarPerformStep(1)'或0

至極(它的工作原理(線程部分 - 女巫真棒順便說一句),與不執行執行步驟的小缺陷 - 或任何其他UI更改我在私人小組中的代碼setForm1PrgBarPerformStep()

有沒有很好的理由呢?

回答

3

當你的線程首先命中SetLabelText2,InvokeRequired將是真實的,從而

Invoke(New UpdateDelegate(AddressOf SetLabelText2)) 

將被調用。

現在,將Invoke調用內部實際發生的是,你的線程將委託傳遞給UI線程的任務。因此,第二次對SetLabelText2的遞歸調用將由UI線程完成,並且您的線程剛好位於並等待UI線程從SetLabelText2返回。所以,你的UI模塊,因爲UI線程將處於一個循環,設置標籤文本和睡眠,並沒有得到一個機會來處理消息/事件。

作爲一個解決方案,而不是睡眠(200),你可以調用Application.DoEvents()的循環中,但這可能有副作用,不建議使用。

更好的解決方案是限制調用到絕對必要的UI電話,在你的榜樣:

Private Sub SetLabelText2() 
    For i = 1 To 110 
     'Label2.Text = Text 
     Invoke(MyDelegateThatDoesNothingButSettingTheLabelText) 
     Threading.Thread.Sleep(200) 
    Next 
End Sub 

現在睡覺會被你的線程來完成,你的用戶界面保持響應。

+0

Aliright,我會嘗試這種解決方案,因爲我不知道如何即刻調用所有的UI調用內的功能,在我的設置標籤文本子內...你說每個用戶界面變化不得不創建一個單獨的子,並調用它們? – Pakk

+0

@ user2236967您不必爲每次調用需要調用的方法/設置器/獲取器的單個調用創建一個子對象。您可以捆綁這些電話。只要確保你的Invoke()方法做的工作很少,並且很快就會返回,因爲每個Invoke()調用都會阻止UI的完成。在調用「Invoke()' – wborgsm

+0

」)之間完成的艱難工作哇,這很糟糕的樣子,將把這個放到上面的編輯中 – Pakk

0

您的第一個問題是由於Invoke,SetLabelText2中的Sleep在UI線程上被調用,而不是在後臺線程上。這將導致用戶界面顯示鎖定。新線程僅用於啓動SetLabel,但工作幾乎立即返回到調用線程。相反,您需要調用循環內的後臺任務,並將每個標籤更新委派回UI。

其次,你不應該在這個例子中創建顯式線程。從.Net 4開始,您應該使用Tasks來代替。要像使用Thread.Sleep一樣模擬長時間運行的操作,請使用Task.Delay(200),然後等待或等待顯式調用.Wait。請記住在後臺線程上安排延遲並將其委託回UI更新。

+0

睡眠是從別人的解決方案,但感謝您的信息。 ----我的錯,我猜測我在代碼的頂部有一段睡眠。 – Pakk

0

好的,多虧了本節的評論和一些研究的幫助,我終於明白了這一點。

我有點被運行的UI線程欺騙了一點點,只是突然做了一個循環或短時間的繁重的工作天氣,這裏有一些代碼 - 希望這可以幫助其他人。

Public t2 As Threading.Thread ' Instantiating the Thread. I do this in my Modules 
           ' You will want to do this for all threads needed. 

'You would then go through your program like normal until you hit a heavy process eating point, 
'For me it was when i was converting images and sending them/moving them across the network 

'So to get what i wanted i used this in the middle of my public Function 

    For Each s As String In sFiles 
     c += 1 'This was just a simple file counter for the prg bar 

CheckAgain: 
     If t3 Is Nothing Then 
      t3 = New Thread(New ParameterizedThreadStart(AddressOf DoWork)) 
      t3.Start(s) 
      GoTo NextOne 
     ElseIf t4 Is Nothing Then 
      t4 = New Thread(New ParameterizedThreadStart(AddressOf DoWork)) 
      t4.Start(s) 
      GoTo NextOne 
     ElseIf t5 Is Nothing Then 
      t5 = New Thread(New ParameterizedThreadStart(AddressOf DoWork)) 
      t5.Start(s) 
      GoTo NextOne 
     ElseIf t6 Is Nothing Then 
      t6 = New Thread(New ParameterizedThreadStart(AddressOf DoWork)) 
      t6.Start(s) 
      GoTo NextOne 
     ElseIf t7 Is Nothing Then 
      t7 = New Thread(New ParameterizedThreadStart(AddressOf DoWork)) 
      t7.Start(s) 
      GoTo NextOne 
     ElseIf t8 Is Nothing Then 
      t8 = New Thread(New ParameterizedThreadStart(AddressOf DoWork)) 
      t8.Start(s) 
      GoTo NextOne 
     ElseIf t9 Is Nothing Then 
      t9 = New Thread(New ParameterizedThreadStart(AddressOf DoWork)) 
      t9.Start(s) 
      GoTo NextOne 
     Else 
      GoTo CheckAgain 
     End If 
NextOne: 
    Next 

Sub DoWork(ByVal s As Object) 

     ChangeCompression("Variables for my Function that did alot of work") 
     'System.Threading.Thread.Sleep(10) 

    'This is how i disposed of my threads 

    If Not (t3 Is Nothing) Then 
     t3 = Nothing 
    ElseIf Not (t4 Is Nothing) Then 
     t4 = Nothing 
    ElseIf Not (t5 Is Nothing) Then 
     t5 = Nothing 
    ElseIf Not (t6 Is Nothing) Then 
     t6 = Nothing 
    ElseIf Not (t7 Is Nothing) Then 
     t7 = Nothing 
    ElseIf Not (t8 Is Nothing) Then 
     t8 = Nothing 
    ElseIf Not (t9 Is Nothing) Then 
     t9 = Nothing 
    End If 

End Sub 

並且那一切太吧:) - 希望這可以幫助別人,並感謝所有幫助我讓我的 - 有點多線程完成,葉...我知道有更好的方法,但是這一個作品對我來說:)