2017-10-12 54 views
-2

我有這個代碼,它循環遍歷我的列表中的所有帳戶,然後對每個帳戶使用任務的帳戶做一些事情,以加速此過程。每次程序完成此操作時,我都希望用戶界面更新進度欄。我以前使用Invoke,但它不是最好的選擇,我無法得到它的工作。現在我知道這可以使用後臺工作來完成,但這不是讓應用程序多線程的最佳方式,所以我使用了這種方法。而不是援引我聽說ContinueWith,但我似乎無法得到它的工作,我沒有得到任何錯誤消息只是一個紅色的下劃線。 代碼:VB.net ContinueWith

progressBar.Value = 0 
    Dim tasks As New List(Of Task)() 
    For Each account In combos 
     Dim t As Task = Task.Run(Sub() 
            While checked = False 
             If proxies.Count = 0 Then 
              Exit Sub 
              'Also can't think of a good way to stop searching through accounts when there are no proxies left in my queue. 
             End If 
             Dim proxy As New WebProxy(proxies(0)) 
             proxies.TryDequeue(0) 
             'Do something 
            End While 
            checkedAmount += 1 
            Dim progress As Integer = ((checkedAmount/combos.Count) * 100) 
            Task.ContinueWith(progressBar.Value = progress, TaskScheduler.FromCurrentSynchronizationContext()) 'Error here 
           End Sub) 
     tasks.Add(t) 
    Next 
    Task.WaitAll(tasks.ToArray()) 

我沒有得到任何錯誤代碼如下所示: enter image description here

我也試圖把一個子之類的東西,但鉛不了了之了。 感謝您提前提供任何幫助。與調用

更新的嘗試:

Private Delegate Sub UpdateProgressBarDelegate(ByVal progressBarUpdate As ProgressBar, ByVal value As Integer) 

Dim checkedAmount As Integer = 0 
Dim checked As Boolean = False 
Private Sub startBtn_Click(sender As Object, e As EventArgs) Handles startBtn.Click 
    progressBar.Value = 0 
    Dim tasks As New List(Of Task)() 
    For Each account In combos 
     Dim t As Task = Task.Run(Sub() 
            While checked = False 
             proxies.TryDequeue(0) 
             'do stuff 
            End While 
            checkedAmount += 1 
            Dim progress As Integer = ((checkedAmount/combos.Count) * 100) 
            If Me.InvokeRequired = True Then 
             Me.Invoke(New UpdateProgressBarDelegate(AddressOf UpdateProgressBar), progressBar, progress) 
            Else 
             UpdateProgressBar(progressBar, progress) 
            End If 
            'Task.ContinueWith(progressBar.Value = progress, TaskScheduler.FromCurrentSynchronizationContext()) 
           End Sub) 
     tasks.Add(t) 
    Next 
    Task.WaitAll(tasks.ToArray()) 
End Sub 

Private Sub UpdateProgressBar(ByVal ProgressBarUpdate As ProgressBar, progress As Integer) 
    progressBar.Value = progress 
End Sub 

還不行不知道爲什麼?

+1

'我以前使用Invoke,但它不是最好的選擇' - 呃,是的。這是少數幾種方法之一(或者甚至是唯一的方法),你可以實際調用UI線程。 - 另外,FYI,'Task.ContinueWith()'也需要你調用,因爲它也運行後臺任務/線程。 –

+0

雖然調用不必那麼複雜!你可以編寫一個擴展方法來爲你做所有事情,這樣你只需要**一行**就可以調用。請參閱我的回答以獲取有關調用的更多信息,以及如何簡化它(從_ **訪問UI線程** _開始):https://stackoverflow.com/a/45571728/3740093 –

+0

好的,我有這個現在的代碼,但它甚至不能正常工作?它不會更新,也不會在後臺運行。 – 1ben99

回答

2

現在我知道這可以通過使用一個後臺工作要做,但是這是不是讓你的應用程序的多線程

排序的最佳方式。

BackgroundWorker是單獨運行許多不同任務的糟糕方法。沒有人想爲每個任務處理單獨的BackgroundWorker組件。但一個 BackgroundWorker是一個偉大的方式來產生一個額外的線程來管理所有其他任務和更新進度欄。這是一個簡單的解決方案。

無論哪種方式,您要做的一件事當然就是移動代碼以將ProgressBar更新爲單個任務。把它放在任務內部會違反關注點分離。一旦你這樣做了,你還需要將呼叫更改爲WaitAll(),以便在知道你有多少任務的循環中使用WaitAny(),因此當每個任務完成時仍然可以更新ProgressBar。這樣可能會有修復當前問題的副作用。

Private Async Sub startBtn_Click(sender As Object, e As EventArgs) Handles startBtn.Click 

    Dim tasks As New List(Of Task)() 
    For Each account In combos 
     Dim t As Task = Task.Run(Sub() 
           While Not checked 
            proxies.TryDequeue(0) 
            'do stuff 
           End While 
           End Sub) 
     tasks.Add(t) 
    Next 


    progressBar.Value = 0 
    For i As Integer = 1 To tasks.Count 
     Dim t = Await Task.WhenAny(tasks) 
     tasks.Remove(t) 
     progressBar.Value = (i/combos.Count) * 100 
    Next i 
End Sub 

1這裏的問題說明了我們關心的關注點分離,在所有的原因之一。一旦我解決了這個問題,代碼變得更簡單了,令人沮喪的錯誤消失了。

+0

我很欣賞你的意見,但我更願意至少調用它,因爲我嘗試使用後臺工作,而且速度較慢,並且使得我的UI在執行任務時真的很慢並且很麻煩。 – 1ben99

+0

+1用於編輯。我忘記了Task.WaitAll()調用凍結了UI線程(也就是說,除非用'Await'調用)。 –

+1

@VisualVincent哦,他可能還在那樣做。這個窗臺在UI線程上調用某種WaitX()。這就是爲什麼他應該將其轉移到BackgroundWorker。但至少這促使事情朝着正確的方向發展。 –