试图了解背景工作者:)
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 :(得分: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
答案 1 :(得分: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 ..
答案 2 :(得分: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
编辑:
您无法直接在DoWork方法上使用UI控件。您需要先委托它们,但要显示进度(进度条,标签等)。后台工作者拥有它允许您以安全模式使用UI的方法(ProgressChanged())。
答案 3 :(得分:0)
进度条有点愚蠢和令人困惑。我不得不求助于以相同的形式保留我的所有工作(如果可以的话)。因此,在您的情况下,我可能会尝试以相同的形式在过程中执行系统负载。这对我有用。 我希望它有所帮助。我已经粘贴了一些可能解释它的代码(不能让它在SO中格式化 - 对不起)但简而言之:
<强>声明强>
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
答案 4 :(得分: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上看到它逐渐移动到更高的值但立即移动到更低的值。所以这似乎摆脱了滞后。不幸的是
答案 5 :(得分:0)
为您提供了更好的解决方案,但以下是我用来改变您的想法的更改:
BackgroundWorker
仅执行一次DoWork
事件。因此,请在RunWorkerAsync
事件中再次致电RunWorkerCompleted
。AddressOf
时提供委托,但Control.Invoke
过于笼统,因此您必须指定一个。但是,框架提供了MethodInvoker
。因此,请将SystemLoads
更改为Sub
。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中解决的一些其他问题,具体来说:
ObjectDisposedException
。我尝试过缓解它,但是,最后,我在Form
被处置时忽略了它。Sleep
稍微减少更新,以减少调整表单大小时的迟缓。这是显示Timer
会更好的地方。If InvokeRequired
模式,即使此处不需要。 NB我必须制作自己的控制位置,而且它们现在几乎没有问题。
此外,您必须将PerformanceCounter
更改为系统中至少存在InstanceName
。