Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
476 views
in Technique[技术] by (71.8m points)

c# - How can i use two progressBar controls to display each file download progress and also overall progress of all the files download?

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:TempTestingSatelliteImagesDownload" + 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 is List

This code is working but i want now to add two progressBars the first one will show the overall progress the second one will show each file download progress.

I have already in the designer progressBar1 and progressBar2

But not sure how to use them with the async Task and the await.

What i tried so far:

Added a DownloadProgressChanged event handler:

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:TempTestingSatelliteImagesDownload" + nextIndex + ".jpg");

            }
        }

I added the line:

client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressCallback);

Then in the event:

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

But it's never get to 100% per file download. Each time it's downloading the progressBar is getting to another percentages but never to 100%.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Use IProgress<T> interface and Progress<T> class.

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

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

Here is how to use it in the calling code:

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);
}

Example

To run the following example, create a windows form application and add one Label named label1, one ProgressBar named progressBar and one Button named button1. In a real scenario, you would give your controls more meaningful names. Replace all of the code in your form with this code.

What this simple application does is:

When you press the button, it deletes "Progress.txt" file if it exists. It then calls SomeAsyncRoutine. This routine creates an instance of Progress<double> which implements IProgress<double> interface. It subscribes to the ProgressChanged event. It then calls SomeAsyncMethod(progress) passing the instance progress to it. When the progress is reported, it updates the progressBar1.Value and it updates the label1.Text property.

The SomeAsyncMethod mimics some work. Using a loop starting at 1 and finishing at 100, it writes the loop variable (progress) to a file, sleeps for 100ms and then does the next iteration.

The progress to a file in the bin folder named "Progress.txt". Obviously in a real application you will do some meaningful work.

I kept the method names in the application the same as in the snippet I provided so it is easily mapped.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private async void button1_Click(object sender, EventArgs e)
    {
        File.Delete("Progress.txt");
        await SomeAsyncRoutine();
    }

    async Task SomeAsynMethod(IProgress<double> progress)
    {
        double percentCompletedSoFar = 0;
        bool completed = false;
        while (!completed)
        {
            // your code here to do something
            for (int i = 1; i <= 100; i++)
            {
                percentCompletedSoFar = i;
                var t = new Task(() => WriteToProgressFile(i));
                t.Start();
                await t;
                if (progress != null)
                {
                    progress.Report(percentCompletedSoFar);
                }
                completed = i == 100;
            }
        }
    }

    private void WriteToProgressFile(int i)
    {
        File.AppendAllLines("Progress.txt",
                    new[] { string.Format("Completed: {0}%", i.ToString()) });
        Thread.Sleep(100);
    }

    async Task SomeAsyncRoutine()
    {
        var progress = new Progress<double>();
        progress.ProgressChanged += (sender, args) =>
        {
            // Update your progress bar and do whatever else you need
            this.progressBar1.Value = (int) args;
            this.label1.Text = args.ToString();
            if (args == 100)
            {
                MessageBox.Show("Done");
            }
        };

        await SomeAsynMethod(progress);
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...