2012-08-01 134 views
0

試圖瞭解背景的工人:)VB.net 2010 BackgroundWorker的更新形式進度

Imports System.Threading 
Imports System 
Imports System.IO 
Imports System.Windows.Forms 
Imports System.ComponentModel 
Imports System.Text.RegularExpressions 
Imports System.Text 
Imports System.Diagnostics 
Imports System.Drawing 


Public Class CLViewForm 

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load 
    BackgroundWorker1.RunWorkerAsync() 
End Sub 


Function SystemLoads() 
    Dim PCV As Integer = Convert.ToDecimal(PerformanceCounter1.NextValue()) 
    Me.Label5.Text = PCV & " %" 
    Me.ProgressBar1.Minimum = 0 
    Me.ProgressBar1.Maximum = 100 
    Me.ProgressBar1.Step = 1 
    Me.ProgressBar1.Value = PCV 
    Me.Label6.Text = Now.ToLongTimeString 
    Return 0 
End Function 

Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork 
    Me.Invoke(SystemLoads()) 
    End Sub 
End Class 

的什麼,我試圖做的是隻需要加載一個後臺工作的主要形式 上更新3對事物的基本要點一個進度條,顯示當前的系統負載 文本標籤,顯示由百分之 負載和時鐘

我知道我能做到這一切與一個簡單的定時器,但是當我去加我的其他計時器它往往使形式各種呆滯,所以我想學習如何射擊大多數我想要做的後臺線程中的這些事情。

我對這一切都很陌生,所以我不知道如何調用這些東西,並對其進行線程安全,因此我得到一個錯誤[當然,這就是爲什麼我在這裏問:) :),說 「vb.net跨線程操作無效的控制'progressbar1'從一個線程訪問,而不是它被稱爲」

或其他的東西。

使用代碼示例我提供瞭如何讓後臺線程更新窗體的進度條和%標籤?

TIA

回答

0

創建的後臺工作RunWorkerCompleted和ProgressChanged事件..
C#

this.backgroundWorker.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(/* the event method */); 
this.backgroundWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(/* the event method */); 

另外,不要忘記將WorkerReportsProgress設置爲true ..

+0

謝謝你的回覆,但是我知道的只是VB.net,我對C#的瞭解甚少,這就是爲什麼我問到vb.net的原因。雖然我明白,他們共享很多相同的語法和東西,我不知道如何將它從C#示例「轉換」爲VB。我猜你的意思是我需要某種中間工作人員從後臺進程獲取信息並使用它將信息中介到前臺表單。 – user1567394 2012-08-01 04:12:53

+1

也需要一個workercompleted,如果它始終運行,只要窗體被加載?或者我需要在窗體關閉事件中輸入內容,以便知道殺死後臺進程?那麼如何創建事件呢? – user1567394 2012-08-01 04:16:17

+0

如果您使用的是Microsoft Visual Basic Express,則可以將事件添加到事件窗口。下面介紹如何使用後臺工作器的鏈接http://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx#Y0 – iSa 2012-08-01 06:14:45

1

我試圖在這裏創建一個簡單的例子。你通過使用一個委託在正確的路線,但我認爲你的實施是有點關閉。

具有label,一個progressbar並在其上一個backgroundworker控件的形式是什麼,你需要然後刪除以下代碼:

Private Sub TestForm_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load 
    'Start the worker 
    BackgroundWorker1.RunWorkerAsync() 
End Sub 

Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork 
    'simulate long running processes 
    UpdateStatus(0, "Loading") 
    System.Threading.Thread.Sleep(1000) 
    UpdateStatus(33, "One third of the way through") 
    System.Threading.Thread.Sleep(1000) 
    UpdateStatus(66, "Two thirds of the way through") 
    System.Threading.Thread.Sleep(1000) 
    UpdateStatus(100, "Finished") 
End Sub 

'all calls to update the progress bar and label go through here 
Private Sub UpdateStatus(ByVal progress As Integer, ByVal status As String) 
    Try 
     If Me.InvokeRequired Then 
      Dim cb As New UpdateStatusCallback(AddressOf UpdateStatusDelegate) 
      Me.Invoke(cb, New Object() {progress, status}) 
     Else 
      UpdateStatusDelegate(progress, status) 
     End If 
    Catch ex As Exception 
     MessageBox.Show("There was an error " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error) 
    End Try 
End Sub 

Private Delegate Sub UpdateStatusCallback(ByVal progress As Integer, ByVal status As String) 

'This catually updates the control - modify the paramters and update to suit the control you are using 
Private Sub UpdateStatusDelegate(ByVal progress As Integer, ByVal status As String) 
    ProgressBar1.Value = progress 
    Label1.Text = status 
End Sub 
+0

謝謝!這真的幫助了我。 – Winks 2016-06-10 13:28:24

0

您需要設置:

的BackgroundWorker可以使用進度

的BackgroundWorker可以報告進度

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 
    BW1.RunAsync() 
End Sub 

然後:

Private Sub BW1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BW1.DoWork 

    Dim i as integer = 1 
    Do Until integer = 0 

     IF BW1.CancellationPending = True then 
      MsgBox("Cancelled by user") 
      Exit Sub 
     End If 


     .... 


     BW1.ReportProgress(i) 

    Loop 

End Sub 

顯示進度:

Private Sub BW1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BW1.ProgressChanged 
    Progressbar1.Value = e.ProgressPercentage 
End Sub 

編輯:

不能使用UI控件直接的DoWork方法。你需要首先委託他們,但爲了顯示進度(進度條,標籤等)Backgroundworker擁有它的方法(ProgressChanged()),讓你在安全模式下使用UI。

0

進度條有點愚蠢和混亂。我必須求助於保持我所有的工作形式(如果可以的話)。所以在你的情況下,我可能會嘗試在同一個表單中的程序中執行你的系統負載。這對我來說很有用。 我希望它有幫助。我已經粘貼一些代碼,可能解釋了一點(不能讓它格式化權在所謂對不起),但在一言以蔽之:

  1. 我開始Me.BackgroundWorker.RunWorkerAsync(),它開始 的做工事件。
  2. 調用BackgroundWorker_DoWork(它調用 的PROC你想要做的工作,並彙報)
  3. 你PROC該做的工作,並會使用BackgroundWorker.ReportProgress

宣言

報到
Public Event DoWork As DoWorkEventHandler 
Public Event PrgRprt As ProgressChangedEventHandler 
Public g_intProgress As Integer    

進度條信息

Private Sub btnStepOne_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStepTwo.Click 
    'Calls BackgroundWorker_DoWork, which in turn calls step One 
    Me.BackgroundWorker1.RunWorkerAsync() 
End Sub 

Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker2.DoWork 
    'Called from Me.BackgroundWorker1.RunWorkerAsync() 
    'calls step One proc, where the work is done 
    Call StepOne(strInput) 
End Sub 

Private Function StepOne(strInput as string)as string 
    'this is where I do my work that the progress bar will monitor 
    Dim x as integer  
    For x = 0 to 100 
    'Do your calculations as you loop 
     'This is where you report back to the worker to change progress bar 
     Me.BackgroundWorker1.ReportProgress(x) 
    Next x 

End function 


Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker2.ProgressChanged 

    Me.pbConvertion.Value = e.ProgressPercentage 
    Me.g_intProgress = e.ProgressPercentage 
    Me.pbConvertion.Maximum = "100" 
    Me.pbConvertion.Update() 
    Me.lblProgbar.Text = "Percentage - " & Me.pbConvertion.Value & "% Completed" 
End Sub 

Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted 
    Me.lblProgbar.Text = "Step One Completed" 
End Sub 
0

我使用的技巧是可怕的,但它的工作原理:

  pgbMain.Maximum += 1 
      pgbMain.Value += 2 
      pgbMain.Value -= 1 
      pgbMain.Maximum -= 1 

或者你可以使用:

  i = pgbMain.Value + 1 
      pgbMain.Value = pgbMain.Maximum 
      pgbMain.Value = i 

但後一種方法意味着最終的步驟是爲延遲像平時那樣有不是'落後'的一步。 (否,既不方法視覺檢測。)

可以在在WinForm看到手動調整進度條Value屬性時,它逐漸移動至較高的值,但立即移動到較低。所以這似乎擺脫了滯後。可悲的是。

0

您已經提供了更好的解決方案,但這裏是我用你的觀點工作的變化:

  1. 正如你在評論打聽,BackgroundWorker只執行一次DoWork事件。因此,在RunWorkerCompleted事件再次調用RunWorkerAsync
  2. VB.NET通常提供當你只是使用AddressOf委託,但Control.Invoke是太一般了,所以你必須指定一個。但是,框架提供了MethodInvoker。因此,將SystemLoads更改爲Sub
  3. 一些「百分比」的PerfomaceCounters似乎並沒有堅持0<=%<=100

所以,簡單的變化,讓你越過當前路障給你:

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load 
    BackgroundWorker1.RunWorkerAsync() 
End Sub 

Sub SystemLoads() 
    Dim PCV As Integer = Convert.ToInt32(PerformanceCounter1.NextValue()) 
    Me.Label5.Text = PCV & " %" 
    Me.ProgressBar1.Minimum = 0 
    Me.ProgressBar1.Maximum = 100 
    Me.ProgressBar1.Step = 1 
    Me.ProgressBar1.Value = Math.Min(Math.Max(0, PCV), 100) 
    Me.Label6.Text = Now.ToLongTimeString 
End Sub 

Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork 
    Me.Invoke(New Methodinvoker(AddressOf SystemLoads)) 
End Sub 

Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted 
    BackgroundWorker1.RunWorkerAsync() 
End Sub 

這導致我在這個LinqPad query已經解決其他一些問題,具體如下:

  1. 總是在關閉該窗口得到一個ObjectDisposedException。我試圖緩解,但在最後,我只是忽略了它的Form已被釋放的時候。
  2. 否則迎合例外。
  3. Sleep稍微減少更新,以減少調整窗體大小時的緩慢。這是它顯示Timer會更好的地方。
  4. 使用正確的If InvokeRequired模式,即使這裏不需要它。

NB我必須製作自己的控制位置,因爲它們幾乎沒有問題。 此外,您必須將PerformanceCounter更改爲至少存在於系統上的InstanceName