我有这个大的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
答案 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次。 (每秒更新一个进度条对用户来说很好。)