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 个内容一个进度条,显示当前系统加载一个文本标签,按百分比显示负载和一个时钟

我知道我可以用一个简单的计时器来完成这一切,但是当我添加其他计时器时,它往往会使表单变得迟缓,所以我想学习如何将我想做的大部分事情拍摄到背景中线。

我对这一切都很陌生,所以我不知道如何调用这些东西并对其保持线程安全,因此我收到一个错误[当然,这就是我在这里问的原因:)],上面写着“vb.net cross -线程操作无效控制'progressbar1'从一个线程访问,而不是它被调用“

或类似的东西。

使用我提供的代码示例如何使后台线程更新表单的进度条和 % 标签?

TIA

4

6 回答 6

1

我试图在这里创建一个简单的例子。通过使用委托,您在正确的路线上,但我认为您的实施有点偏离。

您需要一个具有label、 aprogressbar和控件的表单,然后将以下代码放入: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

我使用的技巧很可怕,但它有效:

            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

为后台工作者 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

进度条有点傻和令人困惑。我不得不求助于将我所有的工作保持在相同的形式(如果可以的话)。因此,在您的情况下,我可能会尝试在相同形式的过程中执行您的系统加载。这对我有用。我希望它有所帮助。我已经粘贴了一些可能解释它的代码(不能让它正确格式化,所以很抱歉),但简而言之:

  1. 我从启动 Do-work 事件的 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
于 2013-08-19T03:50:05.020 回答
0

你需要设置:

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

编辑:

您不能直接在 DoWork 方法上使用 UI 控件。您需要首先委派它们,但为了显示进度(进度条、标签等)Backgroundworker 拥有它自己的方法(ProgressChanged()),可以让您在安全模式下使用 UI。

于 2013-03-16T11:33:32.627 回答
0

已经为您提供了更好的解决方案,但这里是我用来让您的想法发挥作用的更改:

  1. 正如您在评论中所问的那样,BackgroundWorker仅执行DoWork一次事件。所以在事件中RunWorkerAsync再次调用。RunWorkerCompleted
  2. VB.NET 通常在你使用的时候提供委托AddressOf,但是Control.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 查询中解决的其他一些问题,特别是:

  1. 总是ObjectDisposedException在关闭窗口。我尝试减轻它,但最后,我只是在Form处理它时忽略了它。
  2. 否则照顾例外情况。
  3. Sleep稍微减少更新,以减少调整表单大小时的迟缓。这是它表明aTimer会更好的地方。
  4. If InvokeRequired即使这里不需要,也要使用正确的模式。

注意,我必须自己制作控制位置,而且它们几乎不能正常工作。此外,您必须将PerformanceCounter至少更改为InstanceName系统上存在的一个。

于 2016-03-22T09:56:02.727 回答