1

我想跟踪在单独线程上进行的下载进度。我知道 System.Net.WebClient 有一个 DownloadStringAsync 方法,但它不能直接用于新的 TPL 类型(TaskFactory、Task 等)。

  • 可以使用 HttpRequest 和 HttpResponse 类跟踪进度吗?
  • 跟踪进度的最佳课程是什么?开销越少越好。
  • 是否有时响应的大小未知,即无法跟踪进度?
  • 每当取得进展时,与 UI 线程同步的最佳方式是什么?

大多数示例显示任务仅在整个任务完成后才更新 UI。这些示例使用延续,采用 UI 同步上下文,避免需要直接使用 Dispatcher。

这个想法是显示一个网格视图(在 WPF 中),其中包含带有进度条的所有下载。我将一直添加新行并更新进度条。我试图避免把这段代码变成一团糟。

4

1 回答 1

3

DownloadStringAsync 和其他事件方法与 .NET 4.0 中的 TPL 配合得非常好(检查 EAP 和 TPL)。通常,TPL 确实通过 TaskCompletionSource 支持事件异步编程。通过 Task.FromAsync 方法支持 Begin/EndXXX 模型 (APM)。您可以找到TPL 和传统 .NET 异步编程的详细说明。

ParallelExtensionExtras库有一组 WebClient 扩展方法,例如 DownloadStringTask,它们返回一个任务,该任务在适当的事件被触发时完成。

以下代码将创建一个任务,该任务将在下载完成时完成:

    public Task<string> DownloadStringTask(WebClient client,Uri uri)
    {
        var tcs = new TaskCompletionSource<string>();
        client.DownloadStringCompleted += (o, a) => tcs.SetResult(a.Result);
        client.DownloadStringAsync(uri);
        return tcs.Task;
    }

至于更新 UI,您可以轻松地使用 DownloadProgressChanged 事件提供反馈,例如:

using (var client = new WebClient())
{
    client.DownloadProgressChanged += (o, a) => Console.WriteLine("{0}",a.ProgressPercentage);

    var task = DownloadStringTask(client,new Uri("http://www.stackoverflow.com"));
    var write=task.ContinueWith(t => Console.WriteLine("Got {0} chars", t.Result.Length));
    write.Wait();
    Console.ReadKey();
}

如果您使用数据绑定向进度条提供进度值,则只需更新进度值属性即可。如果您直接更新进度条(不是一个好主意),您将不得不使用进度条的调度程序来编组对 UI 线程的调用,例如。像这样

    void UpdateProgress(int percent)
    {
        if (progressBar1.CheckAccess())
            progressBar1.Value = percent;
        else
        {                
            progressBar1.Dispatcher.Invoke(new Action(()=>UpdateProgress(percent)));
        }
    }
    ....
    client.DownloadProgressChanged += (o, a) => UpdateProgress(a.ProgressPercentage);
于 2012-05-25T07:14:29.760 回答