I am writing a C# application for uploading and downloading file. The download uses WebClient object and its DownloadAsycDownload method. The download works fine for multiple files. It downloads as much files as I want.
My problem is I am not able to show the progress of all file in different progress bars which are dynamically added to the form's flowlayout control.
Here is my code:
public ProgressBar[] bar;
public int countBar=0;
...
bar[countBar] = new ProgressBar();
flowLayoutPanel1.Controls.Add(bar[countBar]);
countBar++;
request.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownoadInProgress);
request.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadFileCompleted);
request.DownloadFileAsync(new Uri(this.uri), localPath);
byte[] fileData = request.DownloadData(this.uri);
FileStream file = File.Create(localPath);
file.Write(fileData, 0, fileData.Length);
file.Close();
}
public void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
flowLayoutPanel1.Controls.Remove(bar[countBar]);
countBar--;
MessageBox.Show("Download Completed");
}
public void DownoadInProgress(object sender, DownloadProgressChangedEventArgs e)
{
bar[countBar].Maximum = total_bytes;
bar[countBar].Value = (int)e.BytesReceived;
}
You're using a count to index into progress bars, but once one is complete - you remove the last one, where you really should remove the one associated with the file.
I suggest, in this case, using a Dictionary<WebClient, ProgressBar> (might not be WebCliet - should be the type of sender in the events).
...
var progBar = new ProgressBar();
progBar.Maximum = 100;
flowLayoutPanel1.Controls.Add(progBar);
request.DownloadProgressChanged += DownoadInProgress;
request.DownloadFileCompleted += DownloadFileCompleted;
request.DownloadFileAsync(new Uri(this.uri), localPath);
dic.Add(request, progBar);
// You shouldn't download the file synchronously as well!
// You're already downloading it asynchronously.
// byte[] fileData = request.DownloadData(this.uri);
// FileStream file = File.Create(localPath);
// file.Write(fileData, 0, fileData.Length);
// file.Close();
Then, you can remove countBar altogether, and have the new methods:
public void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
// Can remove (WebClient) cast, if dictionary is <object, ProgressBar>
var request = (WebClient)sender;
flowLayoutPanel1.Controls.Remove(dic[request]);
dic.Remove(request);
MessageBox.Show("Download Completed");
}
public void DownoadInProgress(object sender, DownloadProgressChangedEventArgs e)
{
var progBar = dic[(WebClient)sender];
progBar.Value = e.ProgressPercentage;
}
I would use something like this with lambdas, a bit more concise, no need in dictionary:
var webClient = new WebClient();
var pb = new ProgressBar();
pb.Maximum = 100;
flowLayoutPanel1.Controls.Add(pb);
webClient.DownloadProgressChanged += (o, args) =>
{
pb.Value = args.ProgressPercentage;
};
webClient.DownloadFileCompleted += (o, args) =>
{
flowLayoutPanel1.Controls.Remove(pb);
};
webClient.DownloadFileAsync(new Uri(this.uri), localPath);
Related
I was looking into writing data and I used:
System.IO.File.WriteAllBytes(path, GetBytes());
This worked for me but then I wanted to get the progress of the written bytes so I can have a progressbar added to it. I found out that my method can't connect to a progressbar so I decided to use this:
using (BinaryWriter writer = new BinaryWriter(System.IO.File.Open(path, FileMode.Create))) {
byte[] nextBytes = GetBytes(); // your logic to get what to write;
writer.Write(nextBytes);
}
This writes my file succesfully but after a lot of searching (maybe not enough) I can't seem to find out how to keep track of the amount of bytes being written until it's complete. Maybe I'm using a wrong method, if anyone could help me out, would be awesome! (I use a WPF)
Thanks in advance,
Update:
On top of the project I delcare BackgroundWorker()
BackgroundWorker bw;
Then when I start the download I haev this:
bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerAsync(data);
My doWork method:
private void bw_DoWork (object sender, DoWorkEventArgs e) {
downloadData data = (downloadData) e.Argument;
_source = data.DownloadLocation + #"\";
sem.WaitOne();
//enters
updateStatusBar("- Downloading -", data, 0);
Video vid = youtube.GetVideo(data.Url);
byte[] bytes = vid.GetBytes();
using (var writer = new BinaryWriter(System.IO.File.Open(_source + vid.FullName, FileMode.Create))) {
// do your read logic here and read into bytes
var bytesLeft = bytes.Length;
var bytesWritten = 0;
while (bytesLeft > 0) {
int chunk = Math.Min(64, bytesLeft);
writer.Write(bytes, bytesWritten, chunk);
bytesWritten += chunk;
bytesLeft -= chunk;
// calculate progress bar status
bw.ReportProgress(bytesWritten * 100 / bytes.Length, data);
}
}
// Leaves
updateStatusBar("- Done -", data, 100);
sem.Release();
}
My Progresschanged method:
private void bw_ProgressChanged (object sender, ProgressChangedEventArgs e) {
YoutubeData data = (YoutubeData) e.UserState;
updateStatusBar("Downloading: " + e.ProgressPercentage, data, e.ProgressPercentage);
}
Method for updating status bar:
private void updateStatusBar(string txt, downloadData data, int progress) {
_downloadData.Remove(data);
data.ProgressText = txt;
data.Status = progress;
_downloadData.Add(data);
Dispatcher.Invoke(new Action(() => {
lv_DownloadData.ItemsSource = null;
lv_DownloadData.ItemsSource = _youtubeData;
}));
}
But now it freezes my WPF.
Write bytes in chunks and use a BackgroundWorker
using(var writer = new BinaryWriter(System.IO.File.Open(path, FileMode.Create)))) {
// do your read logic here and read into bytes
var bytesLeft = bytes.Length;
var bytesWritten = 0;
while(bytesLeft > 0) {
int chunk = Math.Min(64, bytesLeft);
writer.WriteBytes(array, bytesWritten, chunk);
bytesWritten += chunk;
bytesLeft -= chunk;
// calculate progress bar status
backgroundWorker.ReportProgress(bytesWritten * 100 / array.Length);
}
}
Update
OK, this is purely untested.. but stay we me..
Each BinaryWriterwill do its work on a BackgroundWorker
so you set up the background worker
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
Then you need to start the BackgroundWorker somewhere using bw.RunWorkerAsync()
void bw_DoWork(object sender, DoWorkEventArgs e)
{
// Do your task here
// report its progress
bw.ReportProgress(..);
}
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// update your progress bar here
}
I want to use progress bar in my windows form application. The application will used for downloading a file from a directory to another directory.
But application seem like doing nothing when the user click the download button. So I want to show process of downloanding with progress bar to the user.
I did search for progress bar but I could not find answer of "how to use progress bar for process of downloading".
I would be very pleased if someone explain to me how to use progress bar for process of downloading.
You can use DownloadFileAsync to download file without blocking the main thread and set also an event handler to show the progress in the bar:
private void button1_Click(object sender, EventArgs e)
{
WebClient webClient = new WebClient();
string sourceFile = #"\\server\test.txt";
string destFile = #"\\server2\test2.txt";
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadCompleted);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
webClient.DownloadFileAsync(new Uri(sourceFile), destFile);
}
private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void DownloadCompleted(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("The download is completed!");
}
Or another approach can be using a BackgroundWorker with the property WorkerReportsProgress set to true. Then you should subscribe the events DoWork and ProgressChanged: in the DoWork method you put the code to download or transmit the file on a separated thread and to calculate the progress of the work. In the ProgressChanged method just update the progress bar value. In this case your code will look like this:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// the path of the source file
string sourceFile = #"\\shared\test.txt";
// the path to write the file to
string destFile = #"\\shared2\test2.txt";
FileInfo info = new FileInfo(sourceFile);
// gets the size of the file in bytes
Int64 size = info.Length;
// keeps track of the total bytes downloaded so you can update the progress bar
Int64 runningByteTotal = 0;
using (FileStream reader = new FileStream(sourceFile, FileMode.Open, FileAccess.Read))
{
using (Stream writer = new FileStream(destFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
int iByteSize = 0;
byte[] byteBuffer = new byte[size];
while ((iByteSize = reader.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
{
// write the bytes to the file
writer.Write(byteBuffer, 0, iByteSize);
runningByteTotal += iByteSize;
// calculate the progress
double index = (double)(runningByteTotal);
double total = (double)byteBuffer.Length;
double progressPercentage = (index / total);
int iProgressPercentage = (int)(progressPercentage * 100);
// update the progress bar
backgroundWorker1.ReportProgress(iProgressPercentage);
}
// clean up the file stream
writer.Close();
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
In the button click event (or whatever) that triggers the downloading of the file, you should add this code to start the background worker running asynchronously:
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
The WebClient has a DownloadProgressChanged-Event. Hook it up to the progress bar and you are good to go. MSDN
Remark: You need to use DownloadDataAsync, DownloadFileAsync or OpenReadAsync for the DownloadProgressChanged-Event to fire.
I've created an application that patches my game servers files.
However, I've got 3 problems which I can't solve:
When downloading a new patch, it doesn't update the progressbar instantly, but refreshes it after around 30-40 seconds
I want a label to show how much mega bytes they are downloading, and how much they have so far (for example: 122Mb/750Mb
When downloading, I want a label to show ~% of how much it has downloaded so far
I am not sure how to add number 2 and 3, and the number 1 problem just seems ridiculous, because there's nothing that indicates it should refresh after 30-40 seconds in my coding (at least as far as I know)
My backgroundWorker1_DoWork:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//Defines the server's update directory
string Server = "http://localhost/dl/game-updates/";
//Defines application root
string Root = AppDomain.CurrentDomain.BaseDirectory;
//Make sure version file exists
FileStream fs = null;
if (!File.Exists("version"))
{
using (fs = File.Create("version"))
{
}
using (StreamWriter sw = new StreamWriter("version"))
{
sw.Write("1.0");
}
}
//checks client version
string lclVersion;
using (StreamReader reader = new StreamReader("version"))
{
lclVersion = reader.ReadLine();
}
decimal localVersion = decimal.Parse(lclVersion);
//server's list of updates
XDocument serverXml = XDocument.Load(#Server + "Updates.xml");
//The Update Process
foreach (XElement update in serverXml.Descendants("update"))
{
string version = update.Element("version").Value;
string file = update.Element("file").Value;
decimal serverVersion = decimal.Parse(version);
string sUrlToReadFileFrom = Server + file;
string sFilePathToWriteFileTo = Root + file;
if (serverVersion > localVersion)
{
Uri url = new Uri(sUrlToReadFileFrom);
System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse();
response.Close();
Int64 iSize = response.ContentLength;
Int64 iRunningByteTotal = 0;
using (System.Net.WebClient client = new System.Net.WebClient())
{
using (System.IO.Stream streamRemote = client.OpenRead(new Uri(sUrlToReadFileFrom)))
{
using (Stream streamLocal = new FileStream(sFilePathToWriteFileTo, FileMode.Create, FileAccess.Write, FileShare.None))
{
int iByteSize = 0;
byte[] byteBuffer = new byte[iSize];
while ((iByteSize = streamRemote.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
{
streamLocal.Write(byteBuffer, 0, iByteSize);
iRunningByteTotal += iByteSize;
double dIndex = (double)(iRunningByteTotal);
double dTotal = (double)byteBuffer.Length;
double dProgressPercentage = (dIndex / dTotal);
int iProgressPercentage = (int)(dProgressPercentage * 100);
backgroundWorker1.ReportProgress(iProgressPercentage);
}
streamLocal.Close();
}
streamRemote.Close();
}
}
//unzip
using (ZipFile zip = ZipFile.Read(file))
{
foreach (ZipEntry zipFiles in zip)
{
zipFiles.Extract(Root + "\\", true);
}
}
//download new version file
WebClient webClient = new WebClient();
webClient.DownloadFile(Server + "version.txt", #Root + "version");
//Delete Zip File
deleteFile(file);
}
}
}
My backgroundWorker1_ProgressChanged:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
label1.Text = "Downloading updates...";
}
And my backgroundWorker1_RunWorkerCompleted:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
settings_btn.Enabled = true;
start_btn_disabled.Enabled = false;
start_btn_disabled.Visible = false;
start_btn.Visible = true;
start_btn.Enabled = true;
progressBar1.Value = 100;
label1.Text = "Client is up to date!";
}
Also, a side note: I'm also having a bit problems of updating labels in backgroundWorker2_DoWork?
Any ideas?
Here's some working code which updates a label on Form1 using the BackgroundWorker.
Create a new Windows Form project and drop it in your code and it'll work.
It's super ugly, but it works.
After that, just plug your code into the DoWork method and calculate your value and send to ReportProgress.
Keep in mind that the work done in DoWork method is the actual Background Thread.
That means that in that method (DoWork) you cannot access UI (form) elements because they are on the UI thread.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
backgroundWorker1.DoWork += backgroundWorker1_DoWork;
backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
}
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
button1.Enabled = true;
}
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
backgroundWorker1.RunWorkerAsync();
}
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = e.ProgressPercentage.ToString();
}
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
FakeCountingWork();
}
private void FakeCountingWork()
{
int totalNumber = 100;
int progressCounter = 0;
while (progressCounter < totalNumber)
{
int fakecounter = 0;
for (int x = 0; x < 100000000; x++)
{
fakecounter++;
}
progressCounter++;
backgroundWorker1.ReportProgress(progressCounter);
}
}
}
################################## EDITED TO ADD OTHER FUNCTIONALITY
Okay, here's how you can implement a label which displays the number of bytes downloaded so far.
Add a second label named label2 to your form.
Next alter the following methods from my previous example.
Here we are going to use the UserState to pass an extra value to the ProgressChanged Event. It's very simple. You can see that I'm generating a random number and it will now appear in Label2. This is where you could show your number of bytes.
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = e.ProgressPercentage.ToString();
label2.Text = e.UserState.ToString();
}
private void FakeCountingWork()
{
int totalNumber = 100;
int progressCounter = 0;
Random rnd = new Random();
while (progressCounter < totalNumber)
{
int fakecounter = 0;
for (int x = 0; x < 100000000; x++)
{
fakecounter++;
}
progressCounter++;
updateValue = rnd.Next();
backgroundWorker1.ReportProgress(progressCounter,updateValue);
}
}
I would imagine this is because you are trying to update UI objects on a different thread. HAve you tried using the Dispatcher if using wpf? https://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke(v=vs.110).aspx
or Invoke if using Winforms? https://msdn.microsoft.com/fr-ca/library/zyzhdc6b(v=vs.85).aspx
Edit:
As #daylight pointed out to be, the UI was being updated in the progresschanged event, which executes on the thread which created the background worker, therefore there shouldn't be an issue regarding threading. See https://msdn.microsoft.com/en-us/library/ka89zff4(v=vs.110).aspx for more info
I am developing a WPF, C# application and I have to read a very big CSV file and write to a database. This process takes a long time so I want to at least show a progress bar that grows in size as it nears completition.
Now, I have the following code at the top:
private readonly BackgroundWorker worker = new BackgroundWorker();
Then inside the loop I have this:
worker.WorkerReportsProgress = true;
worker.ReportProgress((100 * i) / 10000);
and I have a private sub like this:
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
prgBar.Value = Math.Min(e.ProgressPercentage, 100);
}
Yet I don't see the progress bar updating or anything happening, program still hangs. Am I doing something wrong?
UPDATE: Tried the MSDN guide here http://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx and I somehow failed to get it working with that example. I adjusted the looping part of course. Heh. It still stays idle and nothing updates. Heck, all I want to do is get a small counter that increases every time a line is read and added.
UPDATED CODE:
private BackgroundWorker bw = new BackgroundWorker();
public Process()
{
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
// Perform a time consuming operation and report progress.
int d = 0;
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
// Set filter for file extension and default file extension
dlg.DefaultExt = ".csv";
dlg.Filter = "CSV File (*.csv)|*.csv";
dlg.Title = "file";
// Display OpenFileDialog by calling ShowDialog method
Nullable<bool> result = dlg.ShowDialog();
if (result == true)
{
// Open document
string filename = dlg.FileName;
List<String[]> fileContent = new List<string[]>();
using (FileStream reader = File.OpenRead(#filename)) // mind the encoding - UTF8
using (TextFieldParser parser = new TextFieldParser(reader))
{
using (SqlConnection conn = new SqlConnection(Classes.PublicVariables.Connection))
{
parser.Delimiters = new[] { "," };
parser.HasFieldsEnclosedInQuotes = true;
while (!parser.EndOfData)
{
string[] line = parser.ReadFields();
fileContent.Add(line);
SqlCommand comm = QUERYANDPARAMETERS
d += 1;
comm.ExecuteNonQuery();
worker.ReportProgress((d * 10));
}
}
}
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lblCount.Content = "Complete";
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.lblCount.Content = (e.ProgressPercentage.ToString() + "%");
}
I am getting an excerption when the worker runs.
An exception of type 'System.NullReferenceException' occurred inSolution.exe but was not handled in user code
Additional information: Object reference not set to an instance of an object.
UPDATE3
Got it working! All I needed was the same code as above but this:
if (bw.IsBusy != true)
{
bw.RunWorkerAsync();
}
else
{
bw_DoWork(null, null);
}
In the event handler for the button press.
This will not compile as-is, but should get you started in the right direction:
private readonly BackgroundWorker worker
= new BackgroundWorker { WorkerReportsProgress = true };
public MainWindow()
{
InitializeComponent();
worker.DoWork += worker_DoWork;
worker.ProgressChanged += worker_ProgressChanged;
}
private void worker_DoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
// Do some long process, break it up into a loop so you can periodically
// call worker.ReportProgress()
worker.ReportProgress(i); // Pass back some meaningful value
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
prgBar.Value = Math.Min(e.ProgressPercentage, 100);
}
is the varible i int? if it is, the value of (100 * i) / 10000 will return 0 while i < 100. and the param of ReportProgress method should be a precent value. you can change it to worker.ReportProgress(i);,try it.
It has been surprisingly hard to find a code example of downloading multiple files using the webclient class asynchronous method, but downloading one at a time.
How can I initiate a async download, but wait until the first is finished until the second, etc. Basically a que.
(note I do not want to use the sync method, because of the increased functionality of the async method.)
The below code starts all my downloads at once. (the progress bar is all over the place)
private void downloadFile(string url)
{
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
// Starts the download
btnGetDownload.Text = "Downloading...";
btnGetDownload.Enabled = false;
progressBar1.Visible = true;
lblFileName.Text = url;
lblFileName.Visible = true;
string FileName = url.Substring(url.LastIndexOf("/") + 1,
(url.Length - url.LastIndexOf("/") - 1));
client.DownloadFileAsync(new Uri(url), "C:\\Test4\\" + FileName);
}
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = bytesIn / totalBytes * 100;
progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
}
What I have done is populate a Queue containing all my urls, then I download each item in the queue. When there are no items left, I can then process all the items. I've mocked some code up below. Keep in mind, the code below is for downloading strings and not files. It shouldn't be too difficult to modify the below code.
private Queue<string> _items = new Queue<string>();
private List<string> _results = new List<string>();
private void PopulateItemsQueue()
{
_items.Enqueue("some_url_here");
_items.Enqueue("perhaps_another_here");
_items.Enqueue("and_a_third_item_as_well");
DownloadItem();
}
private void DownloadItem()
{
if (_items.Any())
{
var nextItem = _items.Dequeue();
var webClient = new WebClient();
webClient.DownloadStringCompleted += OnGetDownloadedStringCompleted;
webClient.DownloadStringAsync(new Uri(nextItem));
return;
}
ProcessResults(_results);
}
private void OnGetDownloadedStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null && !string.IsNullOrEmpty(e.Result))
{
// do something with e.Result string.
_results.Add(e.Result);
}
DownloadItem();
}
Edit:
I've modified your code to use a Queue. Not entirely sure how you wanted progress to work. I'm sure if you wanted the progress to cater for all downloads, then you could store the item count in the 'PopulateItemsQueue()' method and use that field in the progress changed method.
private Queue<string> _downloadUrls = new Queue<string>();
private void downloadFile(IEnumerable<string> urls)
{
foreach (var url in urls)
{
_downloadUrls.Enqueue(url);
}
// Starts the download
btnGetDownload.Text = "Downloading...";
btnGetDownload.Enabled = false;
progressBar1.Visible = true;
lblFileName.Visible = true;
DownloadFile();
}
private void DownloadFile()
{
if (_downloadUrls.Any())
{
WebClient client = new WebClient();
client.DownloadProgressChanged += client_DownloadProgressChanged;
client.DownloadFileCompleted += client_DownloadFileCompleted;
var url = _downloadUrls.Dequeue();
string FileName = url.Substring(url.LastIndexOf("/") + 1,
(url.Length - url.LastIndexOf("/") - 1));
client.DownloadFileAsync(new Uri(url), "C:\\Test4\\" + FileName);
lblFileName.Text = url;
return;
}
// End of the download
btnGetDownload.Text = "Download Complete";
}
private void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
// handle error scenario
throw e.Error;
}
if (e.Cancelled)
{
// handle cancelled scenario
}
DownloadFile();
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = bytesIn / totalBytes * 100;
progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
}
I am struggling to understand where the issue is. If you only call the async method for the first file, won't it only download that file? Why not use the client_downlaodFileCompleted event to initiate the next file download based on some value passed by AsyncCompletedEvents, or maintain a list of downloaded files as a static variable and have client_DownloadFileCompleted iterate tht list to find the next file to download.
Hope that helps but please post more information if I have miunderstood your question.
I would make a new method, for example named getUrlFromQueue which returns me a new url from the queue (collection or array) and deletes it.. then it calls downloadFile(url) - and in client_DownloadFileCompleted I call getUrlFromQueue again.