5

通常、20 000 ~ 100 000 行のデータを返すこの大きな SQL コマンドがあります。しかし、executeMyQuery 関数を呼び出すとすぐに、戻り値の大きさに応じてプログラムが数秒間ハングします。

1列だけ返します。

このコマンドの実行中に進行状況バーを表示するにはどうすればよいですか?

多分スレッドか何かで(私はスレッドの経験がありません)

これが私のコードです(引数は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         
4

2 に答える 2

9

以下は、VB.Net 4.0 で非同期作業を行う方法の簡単な例です。

次のインポートを持つフォームがあるとします。

Imports System.Windows.Forms
Imports System.Threading
Imports System.Threading.Tasks

そのフォームには 2 つのコントロールがあります

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別のスレッドから呼び出すことができるため、クロススレッド呼び出しをチェックすることに注意してください。その場合、メインスレッドで自分自身を呼び出します。

于 2013-05-22T11:53:47.410 に答える
8

クエリの実行中は、実際の進行状況バーを表示できません。MySQL は、クエリが完了するまでにかかる推定時間を提供しません。古い実行を測定し、この情報を使用して進行状況バーを「偽造」することで、時間を見積もることができます。しかし、これは一種のやり過ぎです。ほとんどの場合、ユーザーに「何か」を表示するだけで十分です。ホイールが回転したり、プログレス バーが 2 ~ 3 秒ごとにいっぱいになったりします。

項目を埋めている間に進行状況バーが必要な場合は、あまり変更せずにこれが可能です。プログレス バー コントロールを追加し、"While(myReader.Reader())" ループ内でインクリメントするだけです。これにはクエリよりも時間がかかるとさえ思います。クエリに時間がかかる場合は、列にインデックスがあるかどうかを確認してください。

何かが起こっていることをユーザーに示したい場合は、スレッドを使用できます。.NET には優れた BackgroundWorker() があります。

BackgroundWorker を開始するのは簡単ではありません

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

ここで、backgroundworker の 2 つのイベントを実行する必要があります。

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 カスタム オブジェクトを使用してそれを行うことができます。これについては、詳細なドキュメントをお読みください。progressChanged イベントを頻繁に発生させないでください。それは静かで重く、GUI で何かを変更するたびにアプリケーションが非常に遅くなる可能性さえあります。GUI の処理を​​行わない場合は、1 秒あたり 10 回を超えないように呼び出します。GUI関連の処理を行う場合は、1秒間に最大2回です。(進行状況バーを毎秒更新することは、ユーザーにとって問題ありません。)

于 2013-05-22T10:35:33.443 に答える