how to use progressbar for process of downloading - c#

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.

Related

wpf background worker not displaying data from the method

private void bw_DoWork(object sender, DoWorkEventArgs e)
{
loadtest();
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Progress Bar Window close
pop.Close();
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pop.prgTest.Value = e.ProgressPercentage;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Background Worker code///
bw.WorkerReportsProgress = true;
bw.DoWork += bw_DoWork;
bw.ProgressChanged += bw_ProgressChanged;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
bw.RunWorkerAsync();
//Progress Bar Window
pop.Show();
}
The load test here is...a method that picks up few images from database and displays them. The method works fine if the run the method on page initialisation but its not giving any output when i load them like this in background worker.....here is the method loadtest.
public void loadtest()
{
string query = "select*from question where id='" + 1 + "'";
MySqlConnection conDataBase = new MySqlConnection(constring);
MySqlCommand cmdDataBase = new MySqlCommand(query, conDataBase);
MySqlDataReader myReader;
try
{
conDataBase.Open();
myReader = cmdDataBase.ExecuteReader();
while (myReader.Read())
{
string qid = myReader.GetInt32("id").ToString();
byte[] imgg1q1 = (byte[])(myReader["question"]);
byte[] imgg2q1 = (byte[])(myReader["opt1"]);
byte[] imgg3q1 = (byte[])(myReader["opt2"]);
byte[] imgg4q1 = (byte[])(myReader["opt3"]);
byte[] imgg5q1 = (byte[])(myReader["opt4"]);
MemoryStream mstreamq1 = new MemoryStream(imgg1q1);
MemoryStream mstream1q1 = new MemoryStream(imgg2q1);
MemoryStream mstream2q1 = new MemoryStream(imgg3q1);
MemoryStream mstream3q1 = new MemoryStream(imgg4q1);
MemoryStream mstream4q1 = new MemoryStream(imgg5q1);
q1.BeginInit();
q1.StreamSource = mstreamq1;
q1.CacheOption = BitmapCacheOption.OnLoad;
q1.EndInit();
// Assign the Source property of your image
q_image.Source = q1;
q1opt1.BeginInit();
q1opt1.StreamSource = mstream1q1;
q1opt1.CacheOption = BitmapCacheOption.OnLoad;
q1opt1.EndInit();
option_1.Source = q1opt1;
q1opt2.BeginInit();
q1opt2.StreamSource = mstream2q1;
q1opt2.CacheOption = BitmapCacheOption.OnLoad;
q1opt2.EndInit();
option_2.Source = q1opt2;
q1opt3.BeginInit();
q1opt3.StreamSource = mstream3q1;
q1opt3.CacheOption = BitmapCacheOption.OnLoad;
q1opt3.EndInit();
option_3.Source = q1opt3;
q1opt4.BeginInit();
q1opt4.StreamSource = mstream4q1;
q1opt4.CacheOption = BitmapCacheOption.OnLoad;
q1opt4.EndInit();
option_4.Source = q1opt4;
}
conDataBase.Close();
}
catch
{
}
}
i am using a background worker to display a popup of loading progressbar until the page loads and popup is a function that will display a new popup window which says loading....
the loadtest method works properly everywhere but its not working with the backgroundworker...the funtion loadtest picks some images from database which takes time and i am displaying a popup until the images are getting loaded and the dispalying in option_2.source,option_2.source,option_3.source and option_4.source..........
Don't change control properties directly from a background thread. Instead send them over to the UI thread in order to use them. One way to do this would be via BackgroundWorker.ReportProgress Method (Int32, Object) see also Updating UI with BackgroundWorker in WPF
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
loadtest(sender as BackgroundWorker);
}
and
public void loadtest(BackgroundWorker bw)
{
//... your code
q1.BeginInit();
q1.StreamSource = mstreamq1;
q1.CacheOption = BitmapCacheOption.OnLoad;
q1.EndInit();
// by freezing the image, it will become available to the UI thread
q1.Freeze();
// Don't directly assign the Source property of your image
// q_image.Source = q1;
// Instead, report progress to the UI thread:
bw.ReportProgress.ReportProgress(25, new Tuple<Image, ImageSource>(q_image, q1));
//... your code
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pop.prgTest.Value = e.ProgressPercentage;
// assign the image source on the UI thread
var data = e.UserState as Tuple<Image, ImageSource>;
data.Item1.Source = data.Item2;
}
Edit: added the Freeze() call to image after initialization. This is necessary in order to allow access to the image outside the worker thread where it was created.
As a side note: Please replace your empty catch { } block with some actual error checking... I suppose you just suppressed the relevant exceptions there that would help in identifying the issues.
The backgroundworker has the ReportProgress method with which you can report periodic progress of the background to the UI.
Set the WorkerReportsProgress to true, as this defaults to false.
bw.WorkerReportsProgress = true;
Then hook up the Progress report event to your UI updating method, bw_ProgressChanged, which you are already doing.
bw.ProgressChanged += bw_ProgressChanged;
Then call in the ReportProgress method wherever you want to update the UI in the Do_Work method. Get the worker from the sender object and pass into the loadtest method and call like below.
bw.ReportProgress(progressPercentage); // This would be % completed you want to display.
This should work.

Background Worker Completed Event is firing before it is actually finished doing work

In my application, when a user clicks on a menu item, they are prompted to select a file which I then use a background worker to load and parse with progress being reported to a progress bar during this operation. when the work is complete, I start a new window which i pass the parsed data to. for some reason, the new window is getting opened before the data is parsed and null arguments are passed instead of the data.
my Click Event:
private void CIRCUIT_INSTALATION_SCHEDULED_Click(object sender, RoutedEventArgs e)
{
//prevents users from selecting other menu items
disableAll();
System.Windows.Forms.OpenFileDialog mainExcelFileDialog = new System.Windows.Forms.OpenFileDialog();
mainExcelFileDialog.InitialDirectory = System.Configuration.ConfigurationManager.AppSettings["MainWorkbookDirectory"];
mainExcelFileDialog.Title = "Main Excel File";
mainExcelFileDialog.ShowDialog();
string mainPath = mainExcelFileDialog.FileName;
this.Cursor = System.Windows.Input.Cursors.Wait;
BackgroundWorker cisWorker = new BackgroundWorker();
cisWorker.DoWork += cisWorker_DoWork;
cisWorker.ProgressChanged+=cisWorker_ProgressChanged;
cisWorker.RunWorkerCompleted += cisWorker_RunWorkerCompleted;
cisWorker.RunWorkerAsync(mainPath);
}
my Do Work:
void cisWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
using (FileStream fs = new FileStream(e.Argument.ToString() , FileMode.Open))
{
//copy filestream to memorystream chunk by chunk, reporting progress.
using (MemoryStream ms = new MemoryStream())
{
byte[] buffer = new byte[32768];
int read;
int steps = Convert.ToInt32(fs.Length / buffer.Length);
int i = 0;
while ((read = fs.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
i++;
var progress = new Decimal(i) / new Decimal(steps);
var outOf = Math.Round(progress * 50);
worker.ReportProgress(Convert.ToInt32(outOf));
}
worker.ReportProgress(50);
ms.Position = 0;
//load excel workbook dataset from memorystream
using (var xlr = Excel.ExcelReaderFactory.CreateOpenXmlReader(ms))
{
xlr.IsFirstRowAsColumnNames = true;
mainWorkbook = xlr.AsDataSet();
worker.ReportProgress(100);
}
}
}
}
my on complete:
void cisWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Cursor = System.Windows.Input.Cursors.Arrow;
CircuitInstallationScheduledWindow CIS_Window = new CircuitInstallationScheduledWindow();
CIS_Window.Show();
CIS_Window.Closed += CIS_Window_Closed;
}
EDIT:
I added the mainPath argument to the cisWorker.runWorkerAsync() method. the problem persists unfortunately.
Basically you should check for your data not being null, i.e that no error occurred during DoWork
void cisWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error == null)
{
/* Your mainWorkbook shouldn't be null */
this.Cursor = System.Windows.Input.Cursors.Arrow;
CircuitInstallationScheduledWindow CIS_Window = new CircuitInstallationScheduledWindow();
CIS_Window.Show();
CIS_Window.Closed += CIS_Window_Closed;
}
else
{
// Handle error
}
}
Henk Holterman was right. I was getting an error because I had not set cisWorker.WorkerReportsProgress = true; I still don't know why the error wasn't breaking the debugger since it wasn't being handled, but I did a print statement in my Completed method which helped me track down the culprit.
void cisWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine(e.Error);
this.Cursor = System.Windows.Input.Cursors.Arrow;
CircuitInstallationScheduledWindow CIS_Window = new CircuitInstallationScheduledWindow(mainWorkbook, abfsDatabase);
CIS_Window.Show();
CIS_Window.Closed += CIS_Window_Closed;
}

C# Backgroundworker download progress in label, get bytes in label

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

BackgroundWorker WPF difficulties with Progress Bar

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.

C# Multiple progress bars for multiple file downloads

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

Categories