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

Dea*_*art 5 .net sql vb.net sql-server

我有这个大的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         
Run Code Online (Sandbox Code Playgroud)

Mar*_*ius 8

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

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

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

启动BackgroundWorker非常容易

        Dim bgw As New BackgroundWorker
        bgw.WorkerReportsProgress = true
        bgw.RunWorkerAsync()
Run Code Online (Sandbox Code Playgroud)

现在你必须完成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
Run Code Online (Sandbox Code Playgroud)

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


Jod*_*ell 8

这是一个如何使用VB.Net 4.0进行Asychrounous Work的简要示例.

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

Imports System.Windows.Forms
Imports System.Threading
Imports System.Threading.Tasks
Run Code Online (Sandbox Code Playgroud)

该表格有两个控件

Private WithEvents DoSomthing As Button
Private WithEvents Progress As ProgressBar
Run Code Online (Sandbox Code Playgroud)

在你的应用程序的某个地方我们有一个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
Run Code Online (Sandbox Code Playgroud)

让我们说这项工作是通过点击开始的DoSomething Button.

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

你可能想知道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
Run Code Online (Sandbox Code Playgroud)

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