基于BackgroundWorker Thread概念的VB.Net Winform应用程序 - UI更新问题

时间:2012-01-26 14:21:24

标签: vb.net winforms backgroundworker


我已经构建了一个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

2 个答案:

答案 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的单次调用中包含两个控件(文本框和标签)所需的信息,而不是尝试进行两次调用。