队
我已经构建了一个VB.Net windows应用程序,它将数据上传到数据库并基本上更新了两个控件:
1.一个文本框,每个数据库记录上传时不断更新一行
2.跟踪上传的数据库记录数量的标签。
我使用了BackgroundWorker thread概念,其中线程的bgwWorker_DoWork()方法包含上传的业务逻辑,bgwWorker_ProgressChanged()根据上传更新2个UI控件。
但我面临的问题是我没有获得两个UI控件的完整更新。有时,线程会绕过文本框的更新,有时会更新标签。我可以通过在每个UI控件更新代码之前添加System.Threading.Thread.Sleep(25)来解决此问题。这是解决问题的正确方法吗?或者有什么我想念的吗?
请建议。
以下是这两种方法中的代码:
Private Sub bgwWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgwWorker.DoWork
.................
.................
'Updates database record related update in textbox
System.Threading.Thread.Sleep(25)
updater.eventName = "UpdateStatusBox"
updater.errorMessageToLog = String.Empty
updater.errorMessageToLog += GetErrorMessage(dataTable(rowNumber)("Name").ToString(), ExceptionData)
bgwWorker.ReportProgress(1, updater)
.................
.................
'Updates Status Count in LABEL
System.Threading.Thread.Sleep(25)
updater.eventName = "UpdateStatusBar"
updater.successCount = successCount.ToString()
updater.failureCount = failureCount.ToString()
bgwWorker.ReportProgress(2, updater)
End Sub
Private Sub bgwWorker_ProgressChanged(ByVal sender As System.Object, ByVal e As ProgressChangedEventArgs) Handles bgwWorker.ProgressChanged
Dim updater As UIUpdater = TryCast(e.UserState, UIUpdater)
..........................................
If updater.eventName = "UpdateStatusBar" Then
UpdateStatusBar(updater.successCount, updater.failureCount)
ElseIf updater.eventName = "UpdateStatusBox" Then
txtUpdates.Text = txtUpdates.Text & updater.errorMessageToLog
End If
.....................................
End Sub
答案 0 :(得分:4)
我几乎肯定你的问题是UIUpdater
对象updater
的实例。此对象似乎是全局声明的,因此在调用之间共享。
省略了一些代码,这就是你所拥有的:
updater.eventName = "UpdateStatusBox"
bgwWorker.ReportProgress(1, updater)
updater.eventName = "UpdateStatusBar"
bgwWorker.ReportProgress(2, updater)
虽然您线性调用ReportProgress()
,但它不会立即触发您的ProgressChanged
事件,也不会阻止该方法完成。如果你考虑这样做,那么就会破坏线程的目的。
换句话说,您有一个正在设置属性的全局对象。然后你说“当有人有机会时,用这个做点什么”。然后,您更改该全局对象上的属性,有时会发生 之前 “有人做了某事”。
解决方案要么创建两个全局变量,一个用于每个可能的事件,要么只在需要时创建一个实例变量。我不确定它的线程可以安全地使用全局变量,所以我建议只创建一个实例变量。实际上,传递给ReportProgress
的状态对象可能只是一个字符串。
答案 1 :(得分:0)
我不会在你的DoWork活动中使用睡眠。
您是否在更新后尝试刷新控件?每个控件都有一个Refresh方法,强制重绘。这可能会导致闪烁。
另一种选择是在对ReportProgress的单次调用中包含两个控件(文本框和标签)所需的信息,而不是尝试进行两次调用。