我在使用不同线程上的GUI更新时遇到问题。我的情况是这样的:
我有一个带有单个复选框的主窗体。在Form_Load
事件中,我启动了一个后台工作器。在BackgroundWorker_DoWork
事件中,我调用了一个新类,该类又启动了一个新线程。从这个线程,我试图在Form1上设置复选框的Checked
状态,但是没有任何运气。
到目前为止,我有以下代码示例:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Try
BackgroundWorker1.RunWorkerAsync()
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Try
Do While Not BackgroundWorker1.CancellationPending = True
Dim cl As New HandleClient
Me.Invoke(Sub() Checkbox1.Checked = True)
Loop
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
End Class
Public Class HandleClient
Public Sub startClient()
Dim ctThread As Threading.Thread = New Threading.Thread(AddressOf start)
ctThread.Start()
End Sub
Private Sub start()
While (True)
Try
...
..
Catch ex As Exception
Form1.Invoke(Sub() Form1.Checkbox1.Checked = False) '<== Fails here
End Try
End While
End Sub
End Class
我尝试使用ThreadSafe调用并通过单独的类设置属性,但是我收到一条错误消息,指出我无法使用BeginInvoke或Checkbox只是不更新(没有错误)。
任何帮助表示感谢。
最佳答案
我不确定为什么要从已经为该工作程序启动新线程的后台工作程序启动新线程。好像是多余的线程。 backgroundworker工作线程无法更新UI线程所拥有的控件,这与新句柄客户端线程也无法更新的原因相同。使用后台对象,您可以通过引发后台工作程序的ProgressChanged
事件来更新UI线程,并将更新代码放入处理该事件的方法中。
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Try
BackgroundWorker1.WorkerReportsProgress = true
BackgroundWorker1.RunWorkerAsync()
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
Try
Do While Not worker.CancellationPending = True
' Do the thing that is in the Try block of the HandleClient
Try
' ...
' ..
' Using a value of 1 for true, since you used False in the catch statement
worker.ReportProgress(1)
' Or you can use the overloaded method
worker.ReportProgress(0, True)
Catch ex As Exception
' Form1.Invoke(Sub() Form1.Checkbox1.Checked = False) '<== Fails here
' Using a value of 0 for false
worker.ReportProgress(0)
' Or you can use the overloaded method
worker.ReportProgress(0, False)
End Try
Loop
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Private Sub backgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles backgroundWorker1.ProgressChanged
' If you used the overloaded method, you can delete this case statement
Select Case e.ProgressPercentage
Case 0
Form1.Checkbox1.Checked = True
Case 1
Form1.Checkbox1.Checked = False
Case Else
Form1.Checkbox1.CheckState = CheckState.Indeterminate
End Select
' Or just use the userstate as mention in the comments
Form1.Checkbox1.Checked = DirectCast(e.UserSate, Boolean)
End Sub
End Class
关于vb.net - 尝试更新线程内的GUI(从BackgroundWorker开始),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29009962/