4

次の結果を達成したいと思います-UI スレッドは、時間のかかる操作の進行状況の変更イベントを登録し、メソッド「DoOperationAsync()」を実行します。操作は進行状況の変化を報告しますが、イベントは UI スレッドで呼び出す必要があり、これを達成するのに問題があります。イベントは発生しますが、UI を更新しようとすると、操作を実行しているスレッドからイベントが発生するため、ディスパッチャーを使用する必要があります。私のライブラリが、開発者に先を見越してあらゆる場所でディスパッチャを使用することを強制するべきではないと思います。

基本的には、BackgroundWorker が行うことをしたいと思います。BackgroundWorker は、それを作成したスレッドでどのように ProgressChanged イベントを発生させますか?

4

3 に答える 3

4

.NET 4.5 を使用している場合は、TPL の変更の最新バージョンにアクセスできます。これには、IProgress<T>インターフェイスとその具体的な実装が含まれますProgress<T>。インターフェイスは、2 つの非同期タスク間の進行状況レポート、特にバックグラウンドから UI スレッドへのレポートをサポートするように設計されています。

インターフェース自体は単純で、Report(T)タイプの進行状況の更新をT他のタスクに渡すためのメカニズムとしてメソッドを定義しています。進捗状況を報告する必要がある場合は、操作を呼び出します。パーセンテージの進行状況を渡したい場合は0.1IProgress<float>インスタンスに渡して 10% の進行状況を報告できます。

private async Task BackgroundWorkAsync(IProgress<float> progress)
{
    ...

    progress.Report(0.1); // 10%

    ...

    progress.Report(1.0); // 100%
}

UI スレッドは具体的なProgress<T>インスタンスを作成し、それをバックグラウンド タスクのスコープに渡す必要があります。Progress<T>サブスクライブできるイベントを提供しProgressChangedますが、通常、進行状況が更新されるたびに呼び出されるアクションをコンストラクターに渡します。

var progress = new Progress(value => // set progress bar);

await this.BackgroundWorkAsync(progress);

Progress<T>これは大まかな例ですが、 がコンテキスト (この場合は UI スレッド) に従ってコールバックを同期する方法の魔法を示しています。

于 2013-08-02T13:26:55.730 に答える
2

ABackgroundWorkerを使用しEvent-based asynchronous patternます。

内部的には、 のインスタンスを使用しclass AsyncOperationてイベントを発生させます。

具体的にはAsyncOperation.Post()、適切なスレッドまたはコンテキストでイベントを発生させるために呼び出します。

ライブラリコードでそれを行うことができるはずです。

于 2013-08-02T12:27:19.493 に答える
0

かなり前のことで、どのように行ったかを正確に覚えているコードはありませんが、これが私が行ったことの基礎です。バックグラウンド ワーカーを作成した UI オブジェクトで、進行状況が報告されたときにトリガーされるメソッドも作成しました。次に、バックグラウンド ワーカーで、読み取って UI に挿入できるパブリック プロパティを設定します。

public class myUIFormControlWhatever
{
   ...
   public void CallTheBackgroundWorker()
   {
      myBackgroundWorker bgw = new myBackgroundWorker();
      // attach "listening" when the background worker reports changes
      bgw.ProgressChanged += thisObjectShowChangedProgress;
      bgw.RunWorkerAsync();
   }

   protected void thisObjectShowChangedProgress( object sender, ProgressChangedEventArgs e )
   {
      this.SomeTextShownOnUI = ((myBackgroundWorker)sender).ExposedProperty;
   }
}


public class myBackgroundWorker : BackgroundWorker
{
   public myBackgroundWorker()
   {
      WorkerReportsProgress = true;
      // hook up internal to background worker any strings
      // you want to expose once reporting and any other listeners are out there.
      ProgressChanged += StatusUpdate;
   }

   protected void StatusUpdate( object sender, ProgressChangedEventArgs e )
   {
      // set property to what you want any other listeners to grab/display
      ExposedProperty = "something you are handling internally to background worker";
   }

   public string ExposedProperty
   { get; protected set; }

}

繰り返しますが、これのほとんどは、署名を思い出せなかったイベントハンドラーパラメーター引数のルックアップを使用したメモリからのものです。そのため、UI はバックグラウンド ワーカーを作成しますが、「ProgressChanged」イベントに接続することで報告された変更をリッスンします。そのため、バックグラウンド ワーカーが処理を行うと、UI コンポーネントは、バックグラウンド ワーカー自体である「オブジェクト センダー」パラメーターから読み取るために表示されるプロパティを参照して、独自のセグメントを処理します。

于 2013-08-02T12:46:56.940 に答える