2013-05-22 126 views
3

我有這個大的SQL命令,通常會返回20 000到100 000行的數據。 但是,只要我調用executeMyQuery函數,程序就會掛起幾秒鐘,具體取決於返回的大小。如何在執行大的SQLCommand時顯示進度條VB.Net

我只返回一列。

如何在運行此命令時顯示進度欄?

在一個線程或東西

也許(我有一個線程沒有經驗)

這裏是我的代碼(該參數從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

'Reader'將返回第一行,當您通過調用'myReader.Read'來枚舉行時,您需要增加一個進度條。 SQL部分已經不一樣了。但是,如果希望對數據進行讀取時用戶可以看到進度條的更改,則需要在後臺線程中運行'executeMyQuery',以使主GUI線程空閒,以在觸發時更新進度欄通過增加進度來改變事件。 – Jodrell

+0

謝謝,但我不知道如何使用線程...嘗試了他們,並得到我的控件不屬於線程等錯誤 –

+0

你不知道有多少行將返回,直到查詢完成,所以你贏了'無法展示實際進展。您可以顯示估計的進度或只是指示活動。 – Jodrell

回答

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 

比方說這項工作是由的DoSomethingButton點擊開始。

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可以從另一個線程中調用,它會檢查跨線程調用。在這種情況下,它會在主線程上自行調用。

+0

謝謝你們的努力:) –

+0

@DeanHart,請注意,這實際上是Marius的答案中的'BackgroundWorker'爲你所做的。當你觸發'ProgressChanged'時,它會在實例化它的線程上調用處理程序。 – Jodrell

7

在查詢執行你無法展示真正的進度條。 MySQL不會提供任何估計查詢將花費多長時間。您可以通過測量您的舊跑步數據並用這些信息「僞造」進度條來估計時間。但這有點矯枉過正。在大多數情況下,向用戶顯示「某物」就足夠了。就像輪子旋轉或每2-3秒填充一次進度條一樣。

如果您想在填充項目時使用進度條,則可以在不做太多改變的情況下進行。只需添加一個進度條控件,並在「While(myReader.Reader())」循環中增加它。我甚至懷疑這需要更長的時間然後查詢。如果查詢需要很長時間,請檢查列上是否有索引!

如果您想向用戶顯示正在發生的事情,您可以使用一個線程。 .NET有一個很好的BackgroundWorker()。

這是faily容易啓動一個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 

Remeber,在DoWork的功能裏面,你不能訪問任何GUI的東西。不要在這裏放置消息框,不要直接更改progressBar。總是使用bgw.progressChanged事件。 如果要將bgw.doWork中的消息發送給GUI,則可以使用reportProgress自定義對象來完成此操作。 PLZ閱讀進一步的文件。 不要經常提高progressChanged事件。它很沉重,如果你改變GUI中的某些東西,每次你的應用程序甚至會變得非常慢。如果它不做GUI的話,我會試着每秒調用它不超過10次。每秒至多2次,如果它有GUI的東西。 (每秒更新一次進度條對用戶來說都很好。)