【问题标题】:VB.Net Winform Application based on BackgroundWorker Thread concept - UI update issue基于BackgroundWorker Thread概念的VB.Net Winform应用程序-UI更新问题
【发布时间】:2012-01-26 14:21:23
【问题描述】:

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

【问题讨论】:

    标签: vb.net winforms backgroundworker


    【解决方案1】:

    我几乎可以肯定您的问题是您的 UIUpdater 对象实例updater。该对象似乎是全局声明的,因此在调用之间共享。

    省略一点代码,这就是你所拥有的:

    updater.eventName = "UpdateStatusBox"
    bgwWorker.ReportProgress(1, updater)
    
    updater.eventName = "UpdateStatusBar"
    bgwWorker.ReportProgress(2, updater)
    

    虽然您以线性方式调用ReportProgress(),但它不会立即触发您的ProgressChanged 事件,也不会阻塞直到该方法完成。如果您考虑一下,这样做会破坏线程的目的。

    换句话说,您有一个要设置属性的全局对象。然后你说“当有人有机会时,用这个做点什么”。然后,您更改该全局对象上的属性,有时这会发生在“有人做了某事”发生之前。

    解决方案是创建两个全局变量,一个用于每个可能的事件,或者只在需要时创建一个实例变量。我不确定它的线程是否可以安全地使用全局变量,所以我建议只创建一个实例变量。实际上,您传递给ReportProgress 的状态对象可能只是一个字符串。

    【讨论】:

    • 你绝对是正确的。我理解我的代码的问题,并感谢您以如此美妙的方式向我解释!祝贺你!!! :)
    【解决方案2】:

    我不会在你的 DoWork 活动中使用睡眠。

    您是否尝试过在更新后刷新控件?每个控件都有一个强制重绘的 Refresh 方法。这可能会导致闪烁。

    另一种选择是在对 ReportProgress 的一次调用中包含两个控件(文本框和标签)所需的信息,而不是尝试进行两次调用。

    【讨论】:

    • 嘿 BenR - 感谢您的建议。正如 Chris 建议的那样,问题在于所有这些 ProgessUpdates 调用都使用了相同的 UIUpdater 对象。这间接地使线程概念无效,就像我编写代码的方式一样。干杯! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-02
    • 1970-01-01
    • 2011-02-28
    • 2023-03-10
    相关资源
    最近更新 更多