【问题标题】:ProgressBar Woes. Getting UI thread to update while reading database进度条问题。在读取数据库时让 UI 线程更新
【发布时间】:2011-08-08 17:54:08
【问题描述】:

我无法更新进度条。只要有一个移动的选框栏,我就可以了。基本上,我正在阅读 SqliteReader.vb 类中的数据库例程。我是 Visual Basic 的新手,我确定我需要使用 worker_DoWork 例程,但我不确定如何将来自 Form1: graphData、graphComputations、m_debug 的变量公开给 worker_DoWork 子程序。这通常是怎么做的?

Public Class SqliteReader
   Public Sub ReadDataBase
     End Sub
End Class

这是更新主窗体 Form1.vb 上的图形(zedgraph 元素)。我像这样从主窗体调用进度条:

    ProgressBar.Initialize(channelArray, computationArray, m_debug)        

ProgressBar.vb 下面:

Partial Public Class ProgressBar
    Dim DataAcquisition As New SqliteReader
    Dim WithEvents worker As New BackgroundWorker

Public Sub Initialize(ByRef graphData As Channels(), ByRef graphComputations As Computations(), ByVal m_debug As Integer)
    DataAcquisition = SqliteReader.GetInstance()
    Me.Show()
    Me.Update()
    Dim Update_Thread As Thread(AddressOf Update_ThreadExecute)

    Update_Thread.Priority = ThreadPriority.Normal
    Update_Thread.Start()
    DataAcquisition.ParseEntireDatabase(graphData, graphComputations, m_debug)
    Me.Close()
End Sub


Private Sub ProgressBarStart(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      DataAcquisition = SqliteReader.GetInstance()
      progress.Style = ProgressBarStyle.Marquee
      worker.WorkerReportsProgress = True
      worker.WorkerSupportsCancellation = True
      worker.RunWorkerAsync()
  End Sub

  Private Sub worker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles worker.DoWork
         Dim worker As BackgroundWorker = DirectCast(sender, BackgroundWorker)
         DataAcquisition = SqliteReader.GetInstance()
         ' I probably need 
         ' DataAcquisition.ParseEntireDatabase(graphData, graphComputations, m_debug)
         ' here... but how do I expose graphdata, graphcomputations and m_debug to this sub?
         End Sub

  Private Sub worker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles worker.ProgressChanged
      dataProgress = CInt(((DataAcquisition.currentRow + 1) / DataAcquisition.totalRows) * 100)
      progress.Value = dataProgress
  End Sub

【问题讨论】:

    标签: vb.net progress-bar


    【解决方案1】:

    RunWorkerAsync has a second version that takes a parameter.您可以使用它来传递您的工作人员需要的任何值(或引用)。

    也就是说,您不应该从工作人员内部更新表单元素。当您希望 UI 更新时,您的工作人员应该触发 ProgressChanged 事件,并在那里处理它。 That one also has a version that can send a value back.(如果您发回数组、列表或自定义类,则可以返回许多值。)

    最后一步是您需要实际触发 ProgressChanged。 DataAcquisition.ParseEntireDatabase 可能不会这样做,在这种情况下,使用它不会允许此方法起作用。

    【讨论】:

    • 谢谢。那行得通。我最终直接从 SqlReader 类中触发了 ProgressChanged。
    • 嗨@svaha你能分享你的解决方案吗?
    【解决方案2】:

    如果graphData, graphComputations, m_debug 已经是ProgressBar 的成员,而worker_DoWorkProgressBar 的成员,那么您无需再做任何事情。您应该可以直接访问它们。

    【讨论】:

    • 不幸的是,他们是 Form1 的成员。 Form1 有我的 zedgraph(正在更新的图表)。如果没有 Form1 的成员,我认为我无法更新图表。
    • 好的,我现在明白了。但是您通过initialize 函数发送这些变量。如果您在ProgressBar 中创建成员变量,那么您可以在初始化函数中保存对这些值的引用。然后你可以从worker_DoWork 引用它们。
    【解决方案3】:

    对于上面的 Rapunzo.. 我的最终解决方案是这样的:

    Partial Public Class ProgressBar
    Dim _mDataAcquisition As New SqliteReader
    Public Property DataProgress As Integer = 0
    Dim WithEvents _mProgressWorker As New BackgroundWorker
    Public Sub Initialize(ByRef graphData As List(Of Channels), ByRef auxData As List(Of Channels), _
                          ByRef graphComputations As List(Of Computations))
        _mDataAcquisition = SqliteReader.GetInstance()
        Show()
        Update()
        _mDataAcquisition.ParseEntireDatabase(graphData, auxData, graphComputations)
        Close()
    End Sub
    Private Sub ProgressBarStart(ByVal sender As System.Object, ByVal e As EventArgs) Handles MyBase.Load
        progress.Style = ProgressBarStyle.Blocks
        _mProgressWorker.WorkerReportsProgress = True
        _mProgressWorker.WorkerSupportsCancellation = True
        _mProgressWorker.RunWorkerAsync()
        progress.Visible = True
        progress.Maximum = 100
        progress.Value = 0
    End Sub
    Public Sub WorkerProgressChanged()
        progress.Value = DataProgress
        Invalidate()
    End Sub
    Private Sub WorkerRunWorkerCompleted(ByVal sender As Object, _
                                         ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _
                                         Handles _mProgressWorker.RunWorkerCompleted
        progress.Visible = False
        progress.Value = 0
        Close()
    End Sub
    

    从那里,只需调用 ProgressBar.Initialize 即可启动它

    更新:

        ProgressBar.DataProgress = CInt((currentIt / totalIt) * 100)
        ProgressBar.WorkerProgressChanged()
    

    结束:

        ProgressBar.DataProgress = 100
        ProgressBar.WorkerProgressChanged()
    

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 2015-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-16
      • 2012-05-22
      相关资源
      最近更新 更多