Before i tried to check if progressBar2 that show overall download progress is at 100% but it's not really working. Is there another way more sure way to check it ?
private void btnDownload_Click(object sender, EventArgs e)
{
//urll.Add("http://download.thinkbroadband.com/1GB.zip");
btnDownload.Enabled = false;
label7.Text = "Downloading...";
getTotalBytes(countryList);
CreateCountryDateTimeDirectories(newList);
downloadFile(newList);
}
private Queue<string> _downloadUrls = new Queue<string>();
private async void downloadFile(IEnumerable<string> urls)
{
foreach (var url in urls)
{
_downloadUrls.Enqueue(url);
}
await DownloadFile();
}
private async Task DownloadFile()
{
if (_downloadUrls.Any())
{
WebClient client = new WebClient();
client.DownloadProgressChanged += ProgressChanged;
client.DownloadFileCompleted += Completed;
var url = _downloadUrls.Dequeue();
sw = Stopwatch.StartNew();
if (url.Contains("true"))
{
await client.DownloadFileTaskAsync(new Uri(url), countriesMainPath + "\\" + currentDownloadCountry + "\\" + count + "Infrared.jpg");
}
else
{
await client.DownloadFileTaskAsync(new Uri(url), countriesMainPath + "\\" + currentDownloadCountry + "\\" + count + "Invisible.jpg");
}
return;
}
}
double percentageTotalDownload = 0;
double totalBytesDownloaded = 0;
private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
// Calculate download speed and output it to labelSpeed.
label3.Text = string.Format("{0} kb/s", (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds).ToString("0.00"));
// Update the progressbar percentage only when the value is not the same.
double bytesInCurrentDownload = (double)e.BytesReceived;
double totalBytesCurrentDownload = double.Parse(e.TotalBytesToReceive.ToString());
double percentageCurrentDownload = bytesInCurrentDownload / totalBytesCurrentDownload * 100;
ProgressBar1.Value = int.Parse(Math.Truncate(percentageCurrentDownload).ToString());//e.ProgressPercentage;
// Show the percentage on our label.
Label4.Text = e.ProgressPercentage.ToString() + "%";
// Update the label with how much data have been downloaded so far and the total size of the file we are currently downloading
label10.Text = string.Format("{0} MB's / {1} MB's",
(e.BytesReceived / 1024d / 1024d).ToString("0.00"),
(e.TotalBytesToReceive / 1024d / 1024d).ToString("0.00"));
//Let's update ProgressBar2
totalBytesDownloaded = e.BytesReceived + bytesFromCompletedFiles;
percentageTotalDownload = totalBytesDownloaded / totalBytesToDownload * 100;
progressBar2.Value = (int)percentageTotalDownload;
label6.Text = progressBar2.Value.ToString() + "%";
}
long bytesFromCompletedFiles = 0;
// The event that will trigger when the WebClient is completed
private async void Completed(object sender, AsyncCompletedEventArgs e)
{
await DownloadFile();
}
For example if i have 100 urls and it's start downloading then i want to know in the completed event when all the files downloaded and not only one each time.
You can keep track of how many downloads have been completed in an counter variable. Because of the multiple threads that can access that counter, use the Interlocked class to manipulate that counter.
This are the changes needed in your code:
private int urlCount = 0; // keep track of how many urls are processed
private async void downloadFile(IEnumerable<string> urls)
{
urlCount = 0;
foreach (var url in urls)
{
_downloadUrls.Enqueue(url);
urlCount++;
}
// urlCount is now set
await DownloadFile();
}
And here is the handling of the counter and the check if we are done
private async void Completed(object sender, AsyncCompletedEventArgs e)
{
// urlCount will be decremented
// cnt will get its value
var cnt = System.Threading.Interlocked.Decrement(ref urlCount);
if (cnt > 0) {
await DownloadFile();
}
else
{
// call here what ever you want to happen when everything is
// downloaded
"Done".Dump();
}
}
I haven't understood it very well, but what you are trying to accomplish is that your progress bar is showing progress of download all files and not one file then reset then another file that reset.
If that is the case, then why you do not try foreach file get size and sum it to totalBytesToDownload and then use it in progress bar
So
foreach(string url in urll)
{
//get url file size
totalBytesToDownload = totalBytesToDownload + urlSizeYouGot;
}
Related
I have this issue with my background worker where it only fires after my task is completed and not during. I have made sure to segment the progress properly but its still not firing. I'm not sure what else I can do.
Here is my code:
private int segmentHalf = 0;
private int segmentFull = 0;
public AutoMaticOne()
{
InitializeComponent();
backgroundWorker.WorkerReportsProgress = true;
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
var backgroundWorker = sender as BackgroundWorker;
List<PrintObject> pol = new List<PrintObject>();
var program = programsData.Get(programSelectionInput.Text);
var fields = fieldsData.GetAllByTaskId(program.Id);
pol = printerData.Load(Input, program.Name,fields,program.Delimiter);
pol = pol.OrderBy(x => x.FilePath).ToList();
if (pol != null)
{
for(int i =0;i<pol.Count();i++)
{
segmentHalf = (((i + 1) / pol.Count()) * 100) / 2;
segmentFull = segmentHalf * 2;
backgroundWorker.ReportProgress(segmentHalf);
print.Process(pol[i].FilePath, pol[i].PrinterDriver);
infoInput.Invoke((MethodInvoker)delegate {
infoInput.Text = infoInput.Text + "\r\n" + pol[i].FileName + " - " + pol[i].PrinterDriver;
});
backgroundWorker.ReportProgress(segmentFull);
}
}
}
private void backgroundWorker_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
// Change the value of the ProgressBar to the BackgroundWorker progress.
ProgressBar.Value = e.ProgressPercentage;
ProgressBarLabel.Text = e.ProgressPercentage + "%";
}
private void backgroundWorker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
InputDirectory.Enabled = true;
OutputDirectory.Enabled = true;
InputDirectoryButton.Enabled = true;
OutputDirectoryButton.Enabled = true;
MessageBox.Show("Task has been Completed, Output files can be found at " + OutputDirectory.Text, "Task Completed");
Start.Enabled = true;
}
When I start with 10 files, it seems fine. But when it loads something like 1000, then it only reports the progress at the end.
SegmentHalf and Full are declared above the constructor
As long as i < pol.Count - 1, (i + 1) / pol.Count will be 0. Integer division truncates towards 0. Your code will execute 0 * 100 for all except the last file.
You can fix it like this:
//segmentHalf = (((i + 1) / pol.Count()) * 100) / 2;
segmentHalf = (((i + 1) * 100) / pol.Count) / 2;
The code is working.
But, now I'm showing for each file the download progress in progressBar1.
But I want to add to the designer( added already ) progressBar2 to show the overall download progress. How can I calculate it and display it in progressBar2 ?
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;
using System.Diagnostics;
namespace DownloadFiles
{
public partial class Form1 : Form
{
Stopwatch sw = new Stopwatch();
int count = 0;
PictureBoxBigSize pbbs;
ExtractImages ei = new ExtractImages();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void btnDownload_Click(object sender, EventArgs e)
{
downloadFile(filesUrls);
}
private Queue<string> _downloadUrls = new Queue<string>();
private async void downloadFile(IEnumerable<string> urls)
{
foreach (var url in urls)
{
_downloadUrls.Enqueue(url);
}
await DownloadFile();
}
private async Task DownloadFile()
{
if (_downloadUrls.Any())
{
WebClient client = new WebClient();
client.DownloadProgressChanged += ProgressChanged;
client.DownloadFileCompleted += Completed;
var url = _downloadUrls.Dequeue();
await client.DownloadFileTaskAsync(new Uri(url), #"C:\Temp\DownloadFiles\" + count + ".jpg");
return;
}
}
private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
// Calculate download speed and output it to labelSpeed.
Label2.Text = string.Format("{0} kb/s", (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds).ToString("0.00"));
// Update the progressbar percentage only when the value is not the same.
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());//e.ProgressPercentage;
// Show the percentage on our label.
Label4.Text = e.ProgressPercentage.ToString() + "%";
// Update the label with how much data have been downloaded so far and the total size of the file we are currently downloading
Label5.Text = string.Format("{0} MB's / {1} MB's",
(e.BytesReceived / 1024d / 1024d).ToString("0.00"),
(e.TotalBytesToReceive / 1024d / 1024d).ToString("0.00"));
}
// The event that will trigger when the WebClient is completed
private async void Completed(object sender, AsyncCompletedEventArgs e)
{
if (e.Cancelled == true)
{
MessageBox.Show("Download has been canceled.");
}
else
{
ProgressBar1.Value = 100;
count++;
await DownloadFile();
}
}
}
}
Try adding this method which calculates the total amount of bytes needing to be downloaded (or modify an existing method, whatever you decide):
long totalBytesToDownload = 0;
List<FileInfo> files;
private void getTotalBytes(IEnumerable<string> urls)
{
files = new List<FileInfo>(urls.Count());
foreach(string url in urls)
{
files.Add(new FileInfo(url));
}
files.ForEach(file => totalBytesToDownload += file.Length);
}
So what i've done here is added a method that gets the total amount of bytes to be downloaded, and also created a variable that stores the file size for each file your trying to download, which will be used here in a minute.
First, in your Complete event, we need to create a variable that stores the number of bytes after each file download, which we will use later.
long bytesFromCompletedFiles = 0;
private async void Completed(object sender, AsyncCompletedEventArgs e)
{
if (e.Cancelled == true)
{
MessageBox.Show("Download has been canceled.");
}
else
{
ProgressBar1.Value = 100;
count++;
bytesFromCompletedFiles += files[count - 1].Length;
await DownloadFile();
}
}
And finally, we can update the ProgressChanged event to finish your ProgressBar2:
private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
// Calculate download speed and output it to labelSpeed.
Label2.Text = string.Format("{0} kb/s", (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds).ToString("0.00"));
// Update the progressbar percentage only when the value is not the same.
double bytesInCurrentDownload = double.Parse(e.BytesReceived.ToString());
double totalBytesCurrentDownload = double.Parse(e.TotalBytesToReceive.ToString());
double percentageCurrentDownload = bytesInCurrentDownload / totalBytesCurrentDownload * 100;
ProgressBar1.Value = int.Parse(Math.Truncate(percentageCurrentDownload).ToString());//e.ProgressPercentage;
// Show the percentage on our label.
Label4.Text = e.ProgressPercentage.ToString() + "%";
// Update the label with how much data have been downloaded so far and the total size of the file we are currently downloading
Label5.Text = string.Format("{0} MB's / {1} MB's",
(e.BytesReceived / 1024d / 1024d).ToString("0.00"),
(e.TotalBytesToReceive / 1024d / 1024d).ToString("0.00"));
//Let's update ProgressBar2
double totalBytesDownloaded = e.BytesReceived + bytesFromCompletedFiles;
double percentageTotalDownload = totalBytesDownloaded / totalBytesToDownload * 100;
ProgressBar2.Value = int.Parse(Math.Truncate(percentageTotalDownload)).ToString();
}
Hopefully, this works for you!
I would like to perform the following action in C#:
Read the amount of lines in a specific text file.
Depending on the amount of lines in a text file, read each line and update the progress bar.
This is what I have so far:
private void Form1_Load(object sender, System.EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
int lineCount = 0;
int max = 100;
float percent;
using (var reader = File.OpenText(#"C:\file.txt"))
{
toolStripLabel1.Text = "Initializing...";
while (reader.ReadLine() != null)
{
lineCount++;
}
reader.Close();
for (int i = 0; i < lineCount; i++)
{
percent = (max / lineCount);
toolStripLabel1.Text = i.ToString() + " - " + percent + "%";
bw.ReportProgress(Convert.ToInt32(percent));
percent = percent + percent;
// Thread.Sleep(100);
}
}
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
// progressBar1.Value = (int)(((decimal)currentPosition / (decimal)length) * (decimal)100);
this.Text = e.ProgressPercentage.ToString();
}
Anyone have an idea on how to properly calculate and display the progress bar depending on what line is being read from the file?
Thanks in advance!
There are several problems with your code:
You're first reading the file, then after it has all been read you start updating the progress bar, which doesn't really make any sense.
You're doing integer division in your percentage calculation.
The percentage calculation isn't quite right.
You're updating the ToolStripLabel from the worker thread.
Try this:
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
var files = File.ReadAllLines( #"C:\file.txt" );
for( int i = 0; i < files.Length; i++ )
{
var line = files[i];
// do work on the current line here
int percentage = (int)( ( i / (double)files.Length ) * 100.0 );
bw.ReportProgress( percentage );
}
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
toolStripLabel1.Text = e.ProgressPercentage.ToString() + "%";
this.Text = e.ProgressPercentage.ToString();
}
If the file is very large and it's the actual reading that takes time, you should go back to your original way of reading it, but update the progress for every line instead of after. Though then you're back to the issue of not knowing how many lines there are before you have read the file. In that case - you could estimate the progress based on how many bytes/chars you have read compared to the full size of the file, which you can get without reading it all.
There are a few things you need to do
try this : replace
percent = (max / lineCount);
with this
percent = (100.0 * i / lineCount);
and remove percent = percent + percent;
Try this:
private void InvokeLabel(string text)
{
if (toolStripLabel1.InvokeRequired)
{
toolStripLabel1.Invoke(new Action<string>(InvokeLabel), text);
}
else
{
toolStripLabel1.Text = text;
}
}
For your progress bar it's the same code
I'm trying to show a form that displays a label like "Updating, this window will close once update has finished" to download a few images files. I put this on my form's shown.
private void frmExtraUpdater_Shown(object sender, EventArgs e)
{
for (int i = 1; i < 8; i++)
{
string _EmoticonURL = String.Format("https://dl.dropboxusercontent.com/u/110636189/MapleEmoticons/f{0}.bmp", i);
WebRequest requestPic = WebRequest.Create(_EmoticonURL);
WebResponse responsePic = requestPic.GetResponse();
Image webImage = Image.FromStream(responsePic.GetResponseStream()); // Error
webImage.Save(Application.StartupPath + #"\Images\f" + i + ".bmp");
}
}
However.. once the form is shown, the label doesn't even show because it doesn't load it (It insantly downloades the images. I want it to show the label and only then start the download).
The other problem is that it throws "A generic error occurred in GDI+." on the webImgae.Save part for some reason.
Why's that?
Oh and.. if the folder "Images" does not exist, will it automatically create it?
Thanks!
Here is Jon Skeet suggestion:
System.Net.WebClient webClient = new System.Net.WebClient();
webClient.DownloadFile(String.Format("https://dl.dropboxusercontent.com/u/110636189/MapleEmoticons/f{0}.bmp", i), Application.StartupPath + #"\Images\f" + i + ".bmp");
Use a background worker to update any UI components
BackgroundWorker backTask = new BackgroundWorker();
public frmExtraUpdater()
{
backTask.DoWork += backTask_DoWork;
backTask.RunWorkerCompleted += backTask_RunWorkerCompleted;
}
private void frmExtraUpdater_Shown(object sender, EventArgs e)
{
yourLabel.Text = "Downloading";
backTask.RunWorkerAsync();
}
void backTask_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i < 8; i++)
{
System.Net.WebClient webClient = new System.Net.WebClient();
webClient.DownloadFile(String.Format("https://dl.dropboxusercontent.com/u/110636189/MapleEmoticons/f{0}.bmp", i), Application.StartupPath + #"\Images\f" + i + ".bmp");
backTask.ReportProgress(i * (100 / 8), String.Format("https://dl.dropboxusercontent.com/u/110636189/MapleEmoticons/f{0}.bmp", i));
}
}
void backTask_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
yourLabel.Text = "Downloading" + e.UserState.ToString();
}
void backTask_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Close();
}
You should use an async method, with webrequest async api (if you work with .net 4.5 or sup) or download your images in a background thread to avoid ui thread blocking.
You can try that:
private void frmExtraUpdater_Shown(object sender, EventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (o, d) =>
{
saveImages();
};
worker.RunWorkerCompleted += (o, f) =>
{
this.Close();
};
worker.RunWorkerAsync();
}
private void saveImages()
{
for (int i = 1; i < 8; i++)
{
string _EmoticonURL = String.Format("https://dl.dropboxusercontent.com/u/110636189/MapleEmoticons/f{0}.bmp", i);
WebRequest requestPic = WebRequest.Create(_EmoticonURL);
WebResponse responsePic = requestPic.GetResponse();
Image webImage = Image.FromStream(responsePic.GetResponseStream()); // Error
webImage.Save(Application.StartupPath + #"\Images\f" + i + ".bmp");
}
}
I am attempting to have a progress bar's progress change as the WebClient download progress changes. This code still downloads the file yet when I call startDownload() the window freezes as it downloads the file. I would like for the user to be able to see the progress change as the splash screen loads. Is there any way to fix this so that the user can see the progress of progressBar2 change?
private void startDownload()
{
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
client.DownloadFileAsync(new Uri("http://joshua-ferrara.com/luahelper/lua.syn"), #"C:\LUAHelper\Syntax Files\lua.syn");
}
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;
label2.Text = "Downloaded " + e.BytesReceived + " of " + e.TotalBytesToReceive;
progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
}
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
label2.Text = "Completed";
}
UI Thread will be freezed when you click startDownload(). If you don't want get form freezed, you use startDownload() in another thread and make progress updating in cross-threaded.
One way,
private void startDownload()
{
Thread thread = new Thread(() => {
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
client.DownloadFileAsync(new Uri("http://joshua-ferrara.com/luahelper/lua.syn"), #"C:\LUAHelper\Syntax Files\lua.syn");
});
thread.Start();
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
this.BeginInvoke((MethodInvoker) delegate {
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = bytesIn / totalBytes * 100;
label2.Text = "Downloaded " + e.BytesReceived + " of " + e.TotalBytesToReceive;
progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
});
}
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
this.BeginInvoke((MethodInvoker) delegate {
label2.Text = "Completed";
});
}
Read more multi-threading in Google like this
http://msdn.microsoft.com/en-us/library/ms951089.aspx
-Fixed missing close ); to the bgThread declaration
You should call startDownload() from the UI thread. The whole idea of WebClient.DownloadFileAsync() is that it will spawn a worker thread for you automatically without blocking the calling thread. In startDownload(), you specified callbacks that modify controls which I assume were created by the UI thread. Thus if you call startDownload() from a background thread it will cause problems, because a thread can only modify UI elements it created.
The way it is supposed to work is you call startDownload() from the UI thread, startDownload() as you defined it sets up event call backs that are handled by the UI thread. It then starts the download asynchronously and returns immediately. The UI thread will be notified when the progress changes and the code responsible for updating the progress bar control will execute on the UI thread, and there shouldn't be any problems.
public class ProgressEventArgsEx
{
public int Percentage { get; set; }
public string Text { get; set; }
}
public async static Task<string> DownloadStraingAsyncronous(string url, IProgress<ProgressEventArgsEx> progress)
{
WebClient c = new WebClient();
byte[] buffer = new byte[1024];
var bytes = 0;
var all = String.Empty;
using (var stream = await c.OpenReadTaskAsync(url))
{
int total = -1;
Int32.TryParse(c.ResponseHeaders[HttpRequestHeader.ContentLength], out total);
for (; ; )
{
int len = await stream.ReadAsync(buffer, 0, buffer.Length);
if (len == 0)
break;
string text = c.Encoding.GetString(buffer, 0, len);
bytes += len;
all += text;
if (progress != null)
{
var args = new ProgressEventArgsEx();
args.Percentage = (total <= 0 ? 0 : (100 * bytes) / total);
progress.Report(args);
}
}
}
return all;
}
// Sample
private async void Bttn_Click(object sender, RoutedEventArgs e)
{
//construct Progress<T>, passing ReportProgress as the Action<T>
var progressIndicator = new Progress<ProgressEventArgsEx>(ReportProgress);
await TaskLoader.DownloadStraingAsyncronous(tbx.Text, progressIndicator);
}
private void ReportProgress(ProgressEventArgsEx args)
{
this.statusText.Text = args.Text + " " + args.Percentage;
}
I believe this article will lead you in the right direction http://www.dreamincode.net/forums/topic/115491-download-file-asynchronously-with-progressbar/ .
And in this MSDN Article http://msdn.microsoft.com/en-us/library/ms229675.aspx discusses how "The file is downloaded on the BackgroundWorker component's worker thread, which runs the DoWork event handler. This thread starts when your code calls the RunWorkerAsync method."