5

UI の応答性を維持しながら、データをバックグラウンドでロードできるように Windows フォームを変更しています。データの取得とバインドの両方にかなりの時間がかかります。両方をバックグラウンドで実行するのが理想的ですが、バックグラウンド (メイン スレッドの外側など) で実行する必要がある UI の更新の種類についてはあいまいな点があります。バックグラウンドでのデータ取得とデータ バインディングを示す確かな例は、非常に役立ちます。

4

3 に答える 3

6

取得はバックグラウンドスレッドにプッシュすることができ、プッシュする必要がありますが、すべてを適切に配置するためのパターンがいくつかあります。

基本的に、バックグラウンドスレッドを開始してデータを取得します。データを取得したら、UIスレッドにマージして、実際のUI更新を実行する必要があります(スレッド間のUI更新は悪い悪い悪いです)。

探索するためのバックグラウンドスレッドの3つの基本的な方法があります

  • 最も簡単/最も制限された(そして風変わりなIMO)はBackgroundWorkerコンポーネントです
  • デリゲートとそのBeginInvoke()/ EndInvoke()メソッドを使用すると、使いやすさと柔軟性のバランスがうまく取れます(そして、ThreadPoolスレッドを使用します)。
  • 生のThreadオブジェクトを使用すると、ほとんどの制御が可能になりますが、ThreadPoolThreadsよりもセットアップに時間がかかります。

個人的には、Delegatesオプションに傾倒しています。パターンを理解すれば、操作は非常に簡単です。BackgroundWorkerは前もって素晴らしいように見えますが、いくつかの落とし穴と配管が欠落しているため、予想よりも作業が面倒です。Delegateアプローチの短いサンプルを作成しましょう。まもなく更新します...

編集

ここにいくつかのコードがあります、それはVBにありますが、あなたがC#の人なら、書き写すのに十分簡単なはずです。バックグラウンドスレッドの動作方法については、さらにいくつかのオプションがあるため、ここに2つのサンプルがあります。非ブロッキングが私の好みですが、既存のコードに適合させる場合は、ブロッキングの方が簡単かもしれません。

非ブロッキング、バックグラウンドスレッドが完了すると、コールバックメソッド(GetData_Complete)がUIスレッドで呼び出されます

Sub Main()

    Console.WriteLine("On the main thread")
    Dim dataDelegate As New GetDataCaller(AddressOf GetData)

    Dim iar As IAsyncResult

    ' Non-blocking approach using a callback method
    iar = dataDelegate.BeginInvoke(AddressOf GetData_Complete, Nothing)

End Sub

Private Delegate Sub GetData_CompleteCaller(ByVal iar As IAsyncResult)
Private Sub GetData_Complete(ByVal iar As IAsyncResult)
    If InvokeRequired Then
        Dim invokeDelegate As New GetData_CompleteCaller(AddressOf GetData_Complete)
        Invoke(invokeDelegate, New Object() {iar})
        Exit Sub
    End If

    ' Downcast the IAsyncResult to an AsyncResult -- it's safe and provides extra methods
    Dim ar As System.Runtime.Remoting.Messaging.AsyncResult = DirectCast(iar, System.Runtime.Remoting.Messaging.AsyncResult)

    Dim dataDelegate As GetDataCaller = DirectCast(ar.AsyncDelegate, GetDataCaller)
    Dim result As String = dataDelegate.EndInvoke(iar)

    Console.WriteLine("On the main thread again, background result is: " + result)

End Sub

Private Delegate Function GetDataCaller() As String
Private Function GetData() As String
    Console.WriteLine("On the background thread!")

    For index As Integer = 0 To 2
        Console.WriteLine("Background thread is working")
    Next

    Return "Yay, background thread got the data!"

End Function

サブメイン()のブロック

    Console.WriteLine("On the main thread")
    Dim dataDelegate As New GetDataCaller(AddressOf GetData)

    Dim iar As IAsyncResult

    ' blocking approach; WaitOne() will block this thread from proceeding until the background thread is finished
    iar = dataDelegate.BeginInvoke(Nothing, Nothing)
    iar.AsyncWaitHandle.WaitOne()
    Dim result As String = dataDelegate.EndInvoke(iar)
    Console.WriteLine("On the main thread again, background result is: " + result)

End Sub

Private Sub GetData_Complete(ByVal iar As IAsyncResult)

    ' Downcast the IAsyncResult to an AsyncResult -- it's safe and provides extra methods
    Dim ar As System.Runtime.Remoting.Messaging.AsyncResult = DirectCast(iar, System.Runtime.Remoting.Messaging.AsyncResult)

    Dim dataDelegate As GetDataCaller = DirectCast(ar.AsyncDelegate, GetDataCaller)
    Dim result As String = dataDelegate.EndInvoke(iar)

    Console.WriteLine("On the main thread again, background result is: " + result)

End Sub

Private Delegate Function GetDataCaller() As String
Private Function GetData() As String
    Console.WriteLine("On the background thread!")

    For index As Integer = 0 To 2
        Console.WriteLine("Background thread is working")
    Next

    Return "Yay, background thread got the data!"

End Function
于 2009-07-10T15:12:57.797 に答える
1

サーバーからデータを取得したら、UI スレッドを呼び出して、UI がバインドされている UI コントロールまたはデータセットを更新すると、バックグラウンド スレッドから UI を更新しないでください。

この場合、BackgroundWorker を使用すると、イベントを接続するだけで役立ちます。

HTH

フィル

于 2009-07-10T15:08:20.800 に答える
0

読み込み (「データ ソースからの取得」など) は、デリゲート、バックグラウンド ワーカー、またはその他のプロトコルを使用するかどうかにかかわらず、些細なことかもしれません。しかし、少なくともほとんどのデータ バインドされたコントロールでは、データを非同期に取得することはできますが、準備ができたら、それをバックグラウンドで大きなグリッドにフィードする方法はありますか? それはあなたの質問ですか?もしそうなら、私はあなたが次のいずれかを行うことができると思います:

  • ビュー コントロールを作成 (またはサブクラス化) し、非同期ロード用のインターフェイスを提供します。
  • レコードのフェッチ/フォーマット中に UI がブロックされないように、一度に N レコードのみを表示するページ ビューを実装します。
于 2009-07-10T17:03:45.613 に答える