我想在单独的帖子中跟踪下载的进度。我知道System.Net.WebClient有一个DownloadStringAsync方法,但它不能直接使用新的TPL类型(TaskFactory,Task等)。
大多数示例显示任务仅在整个任务完成后更新UI。这些示例使用continuation来获取UI同步上下文,避免需要直接使用Dispatcher。
这个想法是显示一个网格视图(在WPF中),所有下载都带有进度条。我将一直添加新行并更新进度条。我试图避免把这些代码变成一团糟。
答案 0 :(得分:3)
DownloadStringAsync和其他事件方法在.NET 4.0中使用TPL非常有效(检查EAP和TPL)。通常,TPL确实通过TaskCompletionSource支持事件异步编程。通过Task.FromAsync方法支持Begin / EndXXX模型(APM)。您可以找到详细说明TPL and Traditional .NET Asynchronous Programming。
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);