如何在执行大SQLCommand VB.Net时显示进度条

时间:2013-05-22 10:04:20

标签: .net sql sql-server vb.net

我有这个大的SQL命令,通常返回20 000 - 100 000行数据。 但是只要我调用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         

2 个答案:

答案 0 :(得分:9)

以下是如何使用VB.Net 4.0进行Asychrounous工作的简要示例。

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

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可以从另一个线程调用,所以它会检查跨线程调用。在这种情况下,它会在主线程上调用它自己。

答案 1 :(得分:8)

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

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

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

启动BackgroundWorker非常容易

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

现在你必须完成背景工作者的两个事件:

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内容。不要在这里放置消息框,不要直接更改progressBar。总是使用bgw.progressChanged事件。 如果要将bgw.doWork中的消息发送到GUI,可以使用reportProgress自定义对象来执行此操作。 Plz为此阅读了进一步的文档。 不要过于频繁地引发progressChanged事件。它非常沉重,如果你每次应用程序甚至变得很慢时在GUI中更改某些内容。如果它不做GUI的话,我试着每秒调用它不超过10次。如果它做GUI的话,每秒最多2次。 (每秒更新一个进度条对用户来说很好。)