10

バックグラウンド転送 API を使用する場合、現在のデータ転送を反復処理して、終了 (システム シャットダウン) 後にアプリを再起動した後、データ転送を再開する必要があります。進行状況の情報を取得し、データ転送をキャンセルできるようにするには、AttachAsync を使用してアタッチする必要があります。

私の問題は、データ転送が終了したときにのみ AttachAsync が返されることです。これは、いくつかのシナリオでは理にかなっています。ただし、複数のデータ転送がある場合、リスト内の次の転送は、現在アタッチされている転送が終了するまで開始されません。この問題に対する私の解決策は、AttachAsync().AsTask() が返す Task を従来の方法で処理することでした (await ではなく継続を使用します)。

IReadOnlyList<DownloadOperation> currentDownloads =
   await BackgroundDownloader.GetCurrentDownloadsAsync();
foreach (var downloadOperation in currentDownloads)
{
   Task task = downloadOperation.AttachAsync().AsTask();

   DownloadOperation operation = downloadOperation;
   task.ContinueWith(_ =>
   {
      // Handle success
      ...
   }, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion,
   TaskScheduler.FromCurrentSynchronizationContext());

   task.ContinueWith(_ =>
   {
      // Handle cancellation
      ...
  }, CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled,
  TaskScheduler.FromCurrentSynchronizationContext());

  task.ContinueWith(t =>
  {
     // Handle errors
      ...

  }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted,
  TaskScheduler.FromCurrentSynchronizationContext());
}

それはうまくいきます(実際のコードでは、ダウンロードをListBoxに追加します)。ループはすべてのダウンロードを反復し、StartAsync を実行します。ただし、ダウンロードは実際にはすべて同時に開始されるわけではありません。一度に実行されるのは 1 つだけであり、それが終了した場合にのみ、次のものが続行されます。

この問題の解決策はありますか?

4

2 に答える 2

3

の要点はTask、並列操作のオプションを使用できるようにすることです。await次に、操作をシリアル化するようにコードに指示している場合。待機しない場合は、コードに並列化するように指示しています。

できることは、各ダウンロード タスクをリストに追加して、コードに並列化を指示することです。その後、タスクが 1 つずつ完了するのを待つことができます。

次のようなものはどうですか:

IReadOnlyList<DownloadOperation> currentDownloads = 
    await BackgroundDownloader.GetCurrentDownloadsAsync();
if (currentDownloads.Count > 0)
{
    List<Task<DownloadOperation>> tasks = new List<Task<DownloadOperation>>();
    foreach (DownloadOperation downloadOperation in currentDownloads)
    {
        // Attach progress and completion handlers without waiting for completion
        tasks.Add(downloadOperation.AttachAsync().AsTask());
    }

    while (tasks.Count > 0)
    {
        // wait for ANY download task to finish
        Task<DownloadOperation> task = await Task.WhenAny<DownloadOperation>(tasks);
        tasks.Remove(task);

        // process the completed task...
        if (task.IsCanceled)
        {
            // handle cancel
        }
        else if (task.IsFaulted)
        {
            // handle exception
        }
        else if (task.IsCompleted)
        {
            DownloadOperation dl = task.Result;
            // handle completion (e.g. add to your listbox)
        }
        else
        {
            // should never get here....
        }
    }
}
于 2012-12-28T00:13:07.627 に答える