如何使用两个progressBar控件来显示每个文件的下载进度以及所有文件下载的总体进度?

时间:2016-12-28 21:59:45

标签: c# .net winforms

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Threading;

namespace SatelliteImages
{
    public partial class Form1 : Form
    {
        int count = 0;

        public Form1()
        {
            InitializeComponent();

            ExtractImages ei = new ExtractImages();
            ei.Init();
        }

        private async Task DownloadFile(string url)
        {
            using (var client = new WebClient())
            {
                int nextIndex = Interlocked.Increment(ref count);

                await client.DownloadFileTaskAsync(url, @"C:\Temp\TestingSatelliteImagesDownload\" + nextIndex + ".jpg");
            }
        }

        private async Task DownloadFiles(IEnumerable<string> urlList)
        {
            foreach (var url in urlList)
            {
                await DownloadFile(url);
            }
        }

        private async void Form1_Load(object sender, EventArgs e)
        {
            await DownloadFiles(ExtractImages.imagesUrls);
        }
    }
}

imagesUrls是List

此代码正常运行但我现在想要添加两个progressBars,第一个将显示整体进度,第二个将显示每个文件下载进度。

我已经在设计师progressBar1和progressBar2

但不确定如何将它们与async Task和await一起使用。

到目前为止我尝试了什么:

添加了一个DownloadProgressChanged事件处理程序:

private async Task DownloadFile(string url)
        {
            using (var client = new WebClient())
            {
                int nextIndex = Interlocked.Increment(ref count);
                client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressCallback);
                await client.DownloadFileTaskAsync(url, @"C:\Temp\TestingSatelliteImagesDownload\" + nextIndex + ".jpg");

            }
        }

我添加了一行:

client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressCallback);

然后在事件中:

private void DownloadProgressCallback(object sender, DownloadProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;
        }

但是每个文件下载永远不会达到100%。每次下载progressBar时都会达到另一个百分比,但绝不会达到100%。

1 个答案:

答案 0 :(得分:1)

使用IProgress<T>界面和Progress<T>类。

async Task SomeAsynMethod(IProgress<double> progress)
{
    double percentCompletedSoFar = 0;
    while (!completed)
    {
        // your code here to do something

        if (progress != null)
        {
            prgoress.Report(percentCompletedSoFar);
        }
    }
}

以下是如何在调用代码中使用它:

async Task SomeAsyncRoutine()
{
    var progress = new Progress<double>();
    progress.ProgressChanged += (sender, args) => 
    {
        // Update your progress bar and do whatever else you need
    };

    await SomeAsynMethod(progress);
}

示例

要运行以下示例,请创建一个Windows窗体应用程序,并添加一个名为Label的{​​{1}},一个名为label1的{​​{1}}和一个名为ProgressBar的{​​{1}} {1}}。在实际场景中,您可以为控件提供更有意义的名称。使用此代码替换表单中的所有代码。

这个简单的应用程序的作用是:

当您按下按钮时,它会删除“Progress.txt”文件(如果存在)。然后它会调用progressBar。此例程创建一个实现Button接口的button1实例。它订阅SomeAsyncRoutine事件。然后它调用Progress<double>将实例IProgress<double>传递给它。报告进度后,它会更新ProgressChanged并更新SomeAsyncMethod(progress)属性。

progress模仿了一些工作。使用从1开始并在100结束的循环,它将循环变量(progress)写入文件,休眠100ms然后进行下一次迭代。

名为“Progress.txt”的bin文件夹中文件的进度。显然,在一个真实的应用程序中,你将做一些有意义的工作。

我将应用程序中的方法名称保留为与我提供的代码段相同,因此很容易映射。

progressBar1.Value