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

如何在VB.Net中执行大SQLCommand时显示进度条,.net,sql,sql-server,vb.net,.net,Sql,Sql Server,Vb.net,我有一个很大的SQL命令,它通常返回20000-100000行数据。 但是,只要我调用executeMyQuery函数,程序就会挂起几秒钟,这取决于返回的大小 我只返回一列 运行此命令时,如何显示进度条 可能是在一个线程或什么(我没有线程的经验) 这是我的代码(参数是从3个不同的组合框发送的。selectedItem): 在查询执行期间,您不能显示真正的进度条。MySQL不提供查询查找所需时间的任何估计。你可以通过测量你以前的跑步记录和用这些信息“伪造”进度条来估计时间。但这有点过分了。在大多数

我有一个很大的SQL命令,它通常返回20000-100000行数据。 但是,只要我调用executeMyQuery函数,程序就会挂起几秒钟,这取决于返回的大小

我只返回一列

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

可能是在一个线程或什么(我没有线程的经验)

这是我的代码(参数是从3个不同的组合框发送的。selectedItem):


在查询执行期间,您不能显示真正的进度条。MySQL不提供查询查找所需时间的任何估计。你可以通过测量你以前的跑步记录和用这些信息“伪造”进度条来估计时间。但这有点过分了。在大多数情况下,向用户显示“某物”就足够了。就像车轮旋转或进度条每2-3秒填满一次

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

如果要向用户显示正在发生的事情,可以使用线程。NET有一个很好的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中更改某些内容,应用程序甚至可能会变得非常慢。我试着每秒调用它不超过10次,如果它不做GUI的事情的话。如果它有GUI功能,每秒最多2次。(对于用户来说,每秒钟更新一次进度条就可以了。)

下面是一个如何使用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
在您的应用程序中,我们有一个名为
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
按钮开始的

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

将返回
读取器
和第一行,您需要在调用
myReader.Read来枚举行时增加进度条。SQL部分已经是异步的。但是,如果您希望在读取数据时对进度条的更改对用户可见,则需要在后台线程中运行
executeMyQuery
,以便在通过增加进度触发更改事件时,让主GUI线程自由地更新进度条。谢谢,但我不知道如何使用线程。。。尝试了它们并得到了我的控件不是线程的一部分等错误。在查询完成之前,您不知道将返回多少行,因此无法显示实际进度。您可以显示估计的进度,也可以只显示活动。哪个版本的.net?4.5?旁注:请不要通过构建字符串来构建SQL查询。改用参数!tblname=“something;drop table users;”--”;谢谢大家的努力:)@DeanHart,注意,这就是马吕斯回答中的
后台工作人员为你做的事情。当您触发
ProgressChanged
时,它会在实例化它的线程上重新调用处理程序。
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