0

バックグラウンドワーカーを理解しようとしています:)

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 つのことを更新するバックグラウンド ワーカーをロードすることです 現在のシステムのロードを示すプログレスバー パーセントとクロックでロードを示すテキスト ラベル

単純なタイマーでこれらすべてを実行できることはわかっていますが、他のタイマーを追加すると、フォームがあらゆる種類の動作が遅くなる傾向があるため、やりたいことのほとんどを背景に撮影する方法を学びたいと思いますスレッド。

私はこれらすべてに慣れていないので、これらのものを呼び出してスレッドセーフにする方法がわからないため、[もちろん、それが私がここで質問している理由です:)]というエラーが表示されます。 - スレッド操作が有効ではありません 'progressbar1' が呼び出されたスレッド以外のスレッドからアクセスされました"

またはその趣旨の何か。

私が提供したコード サンプルを使用して、バックグラウンド スレッドでフォームの進行状況バーと % ラベルを更新するにはどうすればよいですか?

ティア

4

6 に答える 6

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
于 2012-08-01T08:17:11.947 に答える
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に設定することを忘れないでください。

于 2012-08-01T03:05:17.027 に答える
0

私が使用するトリックは恐ろしいですが、うまくいきます:

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

または、次を使用できます。

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

しかし、後者の方法は、「後退」ステップがないため、最終ステップが通常どおり遅れることを意味します。(いいえ、どちらの方法も視覚的に検出できません。)

プログレス バーの Value プロパティを手動で調整すると、WinForm で徐々に高い値に移動し、すぐに低い値に移動することがわかります。これでラグが解消されたようです。悲しいことに。

于 2013-08-24T05:02:35.233 に答える
0

以下を設定する必要があります。

バックグラウンドワーカーはプログレスバーを使用できます

バックグラウンド ワーカーは進捗状況を報告できます

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

編集:

DoWork メソッドで UI コントロールを直接使用することはできません。最初にそれらを委任する必要がありますが、進行状況 (プログレスバー、ラベルなど) を表示するために、バックグラウンドワーカーには、UI をセーフモードで使用できる独自のメソッド (ProgressChanged()) があります。

于 2013-03-16T11:33:32.627 に答える
0

より良い解決策が提供されましたが、アイデアを機能させるために使用する変更を次に示します。

  1. コメントで尋ねたように、はイベントを 1 回BackgroundWorkerだけ実行します。そのため、イベントで再度DoWork呼び出します。RunWorkerAsyncRunWorkerCompleted
  2. VB.NET は通常、単に使用する場合にデリゲートを提供しますが、一般的すぎるため、デリゲートを指定する必要がありますAddressOfControl.Invokeただし、フレームワークはMethodInvoker. したがって、に変更SystemLoadsSubます。
  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ここでは必要がなくても、適切なパターンを使用してください。

注意: 私は独自のコントロール ロケーションを作成する必要がありましたが、現状ではほとんど問題ありません。また、PerformanceCounter少なくともInstanceNameシステムに存在する に変更する必要があります。

于 2016-03-22T09:56:02.727 に答える