从后台工作人员调用的另一个 class 更新标签和 ProgressBar 值
Update Label And ProgressBar value from another class invoked in a background worker
你好,我在主窗体的 StatusStrip 中更新进度条和标签时遇到问题。
StatusStrip 内的表单中有 2 个控件:
- 进度条(ToolStripProgressBar)
- ProgressLabel (ToolStripStatusLabel)
基本上我的情况是这样的:
Public Class Main
Public Sub TEST(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles TEST.DoWork
Dim tmp as New NAMESPACE1.CLASS2(VALUES)
End Sub
End Class
Namespace NAMESPACE1
Public Class CLASS2
Public Sub New(VALUES)
Main.Progressbar.Value = 15
Main.ProgressLabel.Text = "hello!"
End Sub
End Class
End Namespace
问题是控件的文本或值在代码中更新(我看到它使用断点),但不是在进度条始终为 0% 且标签始终为无的形式中。
我认为是主窗体的更新或刷新问题。我试过 Main.Refresh() 和 Main.Update() 但不管怎样都行不通。
提前致谢。
这是一个按照 Plutonix 的建议传递对 MAIN 的引用的示例。我故意让你的 伪代码 风格完好无损:
Public Class MAIN
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TEST.RunWorkerAsync()
End Sub
Private Sub TEST_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles TEST.DoWork
Dim tmp As New NAMESPACE1.CLASS2(Me, VALUES) ' <-- Form reference being passed via 1st parameter
End Sub
End Class
Namespace NAMESPACE1
Public Class CLASS2
Private frmMain As MAIN
Public Sub New(ByVal frmMain As MAIN, VALUES)
Me.frmMain = frmMain
Me.frmMain.Progressbar.Value = 15
Me.frmMain.ProgressLabel.Text = "hello!"
End Sub
End Class
End Namespace
您有 2 个问题在进行中。首先是 Main
是一个 class 名称,而不是运行时引用或对象变量。请参阅 Idle_Mind 关于使用 Me
获取运行时对象引用的回答。
第二个问题是,由于Class2
是在DoWork
中创建的,它是在后台线程上创建的,这将阻止它访问UI控件(创建于UI 线程)。你会得到一个非法的跨线程操作异常(即使你没有看到它)。
我建议 Class2
不会做任何使用 ReportProgress
方法无法完成的有用的事情。摆脱它也摆脱了表单引用问题,因为事件是在与 UI 控件相同的线程上引发的:
Private WithEvents bgw As BackgroundWorker
...
' in a button click or whatever starts the worker:
bgw = New BackgroundWorker
bgw.WorkerReportsProgress = True
bgw.RunWorkerAsync(5) ' times to loop
...
Private Sub bgw_DoWork(sender As Object,
e As DoWorkEventArgs) Handles bgw.DoWork
' NOTE
' This code executes on a different thread
' so do not reference UI controls!
' e.Argument is the value passed - amount of work
Dim max As Integer = CInt(e.Argument)
For n As Integer = 1 To max
Threading.Thread.Sleep(250) ' emulates work
' causes the ProgressChanged event to fire:
bgw.ReportProgress(n, String.Format("{0} of {1}", n.ToString, max.ToString))
Next
End Sub
Private Sub bgw_ProgressChanged(sender As Object,
e As ProgressChangedEventArgs) Handles bgw.ProgressChanged
'ProgressChanged fires on the UI thread, so it is safe to
' referenece controls here
TextBox4.Text = e.UserState.ToString
TextBox4.Refresh()
End Sub
粘贴代码,您可以在TextBox
中看到消息的变化。使用您的 ProgressBar
和 ProgressLabel
.
也是一样的
bgw.ReportProgress(n, arg)
第一个参数将映射到 ProgressChanged
事件中的 e.ProgressPercentage
。第二个是可选的 - UserState
。我用它来传递一个字符串用于说明目的(表格已经可以知道工作量,因为它告诉 BGW 要做什么。)
如果Class2
有其他用途,只要在UI线程上创建(在表单中)并在该线程上使用(即在ProgressChanged
事件)。您还需要一种与控件对话的方法,这样您就不必每次都创建一个新控件:
Private myObj As Class2 ' declaration
...
myObj = New Class2(Me) ' instance with frm ref
在class2:
Public Sub Update(value As Integer, msg As String)
frmMain.Progressbar.Value = value
frmMain.ProgressLabel.Text = msg
End Sub
然后在 ProgressChanged
事件中:
myObj.Update(x, y)
其中 x
和 y
是来自任何地方的值和消息。
你好,我在主窗体的 StatusStrip 中更新进度条和标签时遇到问题。
StatusStrip 内的表单中有 2 个控件:
- 进度条(ToolStripProgressBar)
- ProgressLabel (ToolStripStatusLabel)
基本上我的情况是这样的:
Public Class Main
Public Sub TEST(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles TEST.DoWork
Dim tmp as New NAMESPACE1.CLASS2(VALUES)
End Sub
End Class
Namespace NAMESPACE1
Public Class CLASS2
Public Sub New(VALUES)
Main.Progressbar.Value = 15
Main.ProgressLabel.Text = "hello!"
End Sub
End Class
End Namespace
问题是控件的文本或值在代码中更新(我看到它使用断点),但不是在进度条始终为 0% 且标签始终为无的形式中。
我认为是主窗体的更新或刷新问题。我试过 Main.Refresh() 和 Main.Update() 但不管怎样都行不通。
提前致谢。
这是一个按照 Plutonix 的建议传递对 MAIN 的引用的示例。我故意让你的 伪代码 风格完好无损:
Public Class MAIN
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TEST.RunWorkerAsync()
End Sub
Private Sub TEST_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles TEST.DoWork
Dim tmp As New NAMESPACE1.CLASS2(Me, VALUES) ' <-- Form reference being passed via 1st parameter
End Sub
End Class
Namespace NAMESPACE1
Public Class CLASS2
Private frmMain As MAIN
Public Sub New(ByVal frmMain As MAIN, VALUES)
Me.frmMain = frmMain
Me.frmMain.Progressbar.Value = 15
Me.frmMain.ProgressLabel.Text = "hello!"
End Sub
End Class
End Namespace
您有 2 个问题在进行中。首先是 Main
是一个 class 名称,而不是运行时引用或对象变量。请参阅 Idle_Mind 关于使用 Me
获取运行时对象引用的回答。
第二个问题是,由于Class2
是在DoWork
中创建的,它是在后台线程上创建的,这将阻止它访问UI控件(创建于UI 线程)。你会得到一个非法的跨线程操作异常(即使你没有看到它)。
我建议 Class2
不会做任何使用 ReportProgress
方法无法完成的有用的事情。摆脱它也摆脱了表单引用问题,因为事件是在与 UI 控件相同的线程上引发的:
Private WithEvents bgw As BackgroundWorker
...
' in a button click or whatever starts the worker:
bgw = New BackgroundWorker
bgw.WorkerReportsProgress = True
bgw.RunWorkerAsync(5) ' times to loop
...
Private Sub bgw_DoWork(sender As Object,
e As DoWorkEventArgs) Handles bgw.DoWork
' NOTE
' This code executes on a different thread
' so do not reference UI controls!
' e.Argument is the value passed - amount of work
Dim max As Integer = CInt(e.Argument)
For n As Integer = 1 To max
Threading.Thread.Sleep(250) ' emulates work
' causes the ProgressChanged event to fire:
bgw.ReportProgress(n, String.Format("{0} of {1}", n.ToString, max.ToString))
Next
End Sub
Private Sub bgw_ProgressChanged(sender As Object,
e As ProgressChangedEventArgs) Handles bgw.ProgressChanged
'ProgressChanged fires on the UI thread, so it is safe to
' referenece controls here
TextBox4.Text = e.UserState.ToString
TextBox4.Refresh()
End Sub
粘贴代码,您可以在TextBox
中看到消息的变化。使用您的 ProgressBar
和 ProgressLabel
.
bgw.ReportProgress(n, arg)
第一个参数将映射到 ProgressChanged
事件中的 e.ProgressPercentage
。第二个是可选的 - UserState
。我用它来传递一个字符串用于说明目的(表格已经可以知道工作量,因为它告诉 BGW 要做什么。)
如果Class2
有其他用途,只要在UI线程上创建(在表单中)并在该线程上使用(即在ProgressChanged
事件)。您还需要一种与控件对话的方法,这样您就不必每次都创建一个新控件:
Private myObj As Class2 ' declaration
...
myObj = New Class2(Me) ' instance with frm ref
在class2:
Public Sub Update(value As Integer, msg As String)
frmMain.Progressbar.Value = value
frmMain.ProgressLabel.Text = msg
End Sub
然后在 ProgressChanged
事件中:
myObj.Update(x, y)
其中 x
和 y
是来自任何地方的值和消息。