5

我有这个通常返回 20 000 - 100 000 行数据的大 SQL 命令。但是一旦我调用 executeMyQuery 函数,程序就会挂起几秒钟,具体取决于返回的大小。

我只返回一列。

如何在此命令运行时显示进度条?

也许在线程或其他东西中(我没有线程经验)

这是我的代码(参数是从 3 个不同的 combobox.selectedItem 发送的):

    Public Function executeMyQuery(dbname As String, colname As String, tblname As String)
    Try
        ListBox1.Items.Clear()
        If Not String.IsNullOrWhiteSpace(connString) Then
            Using cn As SqlConnection = New SqlConnection(connString)
                cn.Open()
                Using cmd As SqlCommand = New SqlCommand()
                    cmd.Connection = cn
                    Dim qry As String
                    qry = String.Format("select distinct [{0}] from {1}.dbo.{2} where [{0}] is not null", colname, dbname, tblname)
                    cmd.CommandText = qry
                    cmd.CommandTimeout = 0

                    Dim count As Integer
                    Using myReader As SqlDataReader = cmd.ExecuteReader()
                        While (myReader.Read())
                            count += 1
                            ListBox1.Items.Add(count.ToString & ". " & myReader.GetString(0))
                        End While
                    End Using
                End Using
            End Using
        End If
         cn.Close()
    Catch ex As Exception
        MsgBox("Error Occured : " & ex.Message)
        cn.Close()
    End 
End Function         
4

2 回答 2

9

这是一个关于如何使用 VB.Net 4.0 进行异步工作的精简示例。

假设您有一个具有以下导入的表单,

Imports System.Windows.Forms
Imports System.Threading
Imports System.Threading.Tasks

该表单有两个控件

Private WithEvents DoSomthing As Button
Private WithEvents Progress As ProgressBar

在您的应用程序的某个地方,我们有一个Function被调用ExecuteSlowStuff的函数,这个函数相当于您的executeMyQuery. 重要的部分是Action函数用来显示它正在取得进展的参数。

Private Shared Function ExecuteSlowStuff(ByVal progress As Action) As Integer
    Dim result = 0
    For i = 0 To 10000
        result += i
        Thread.Sleep(500)
        progress()
    Next

    Return result
End Function

可以说这项工作是通过单击开始的DoSomething Button

Private Sub Start() Handled DoSomething.Click
    Dim slowStuff = Task(Of Integer).Factory.StartNew(
        Function() ExceuteSlowStuff(AddressOf Me.ShowProgress))
End Sub

你可能想知道ShowProgress从哪里来,那是比较混乱的地方。

Private Sub ShowProgress()
    If Me.Progress.InvokeRequired Then
        Dim cross As new Action(AddressOf Me.ShowProgress)
        Me.Invoke(cross)
    Else 
        If Me.Progress.Value = Me.Progress.Maximum Then
            Me.Progress.Value = Me.Progress.Minimum
        Else
            Me.Progress.Increment(1)
        End If

        Me.Progress.Refresh()
    End if
End Sub

请注意,因为ShowProgress可以从另一个线程调用,它会检查跨线程调用。在这种情况下,它会在主线程上调用自己。

于 2013-05-22T11:53:47.410 回答
8

在查询执行期间,您无法显示真正的进度条。MySQL 不提供任何估计查询需要多长时间才能完成。您可以通过测量您的旧运行并使用此信息“伪造”进度条来估计时间。但这有点矫枉过正。在大多数情况下,向用户显示“某物”就足够了。就像轮子旋转或进度条每 2-3 秒填充一次。

如果您在填充项目时想要一个进度条,则无需进行太多更改即可。只需添加一个进度条控件并在“While(myReader.Reader())”循环中增加它。我什至怀疑这需要比查询更长的时间。如果查询需要很长时间,请检查列上是否有索引!

如果您想向用户显示正在发生的事情,您可以使用线程。.NET 有一个不错的 BackgroundWorker()。

启动 BackgroundWorker 很容易

        Dim bgw As New BackgroundWorker
        bgw.WorkerReportsProgress = true
        bgw.RunWorkerAsync()

现在你必须做backgroundworker的两个事件:

Dim WithEvents bgw As New BackgroundWorker
Dim progressBar As New progressbar

Sub start()
    bgw.WorkerReportsProgress = true
    bgw.RunWorkerAsync()
End Sub

Sub bgw_DoWork(sender As Object, e As DoWorkEventArgs) Handles bgw.DoWork

    ' put your sql code here
    For i As Integer = 0 To 10000
        If i Mod 1000 Then
            bgw.ReportProgress(i / 100)
        End If
    Next

End Sub

Sub bgw_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles bgw.ProgressChanged

    ' put your progress changed events here
    myProgressBar.Value = e.ProgressPercentage

End Sub

请记住,在 DoWork 函数中,您无法访问任何 GUI 内容。不要在此处放置消息框,不要直接更改进度条。始终使用 bgw.progressChanged 事件。如果您想将消息从 bgw.doWork 发送到 GUI,您可以使用 reportProgress 自定义对象来执行此操作。请为此阅读更多文档。不要过于频繁地引发 progressChanged 事件。它很安静,如果您每次都在 GUI 中更改某些内容,您的应用程序甚至可能会变得非常慢。如果它不执行 GUI 操作,我尝试每秒调用它不超过 10 次。并且每秒最多 2 次,如果它执行 GUI 的东西的话。(每秒更新一个进度条对用户来说很好。)

于 2013-05-22T10:35:33.443 回答