private void downloadFile(IEnumerable<string> urls)
{
foreach (var url in urls)
{
_downloadUrls.Enqueue(url);
}
// Starts the download
btnStart.Text = "Downloading...";
btnStart.Enabled = false;
pBarFileProgress.Visible = true;
label2.Visible = true;
label3.Visible = true;
label4.Visible = true;
label7.Visible = true;
DownloadFile();
}
private void DownloadFile()
{
if (_downloadUrls.Any())
{
WebClient client = new WebClient();
client.DownloadProgressChanged += client_DownloadProgressChanged;
client.DownloadFileCompleted += client_DownloadFileCompleted;
url = _downloadUrls.Dequeue();
if (url.Contains("animated") && url.Contains("infra"))
{
string startTag = "animated/";
string endTag = "/infra";
int index = url.IndexOf(startTag);
int index1 = url.IndexOf(endTag);
fname = url.Substring(index + 9, index1 - index - 9);
var countryName = codeToFullNameMap[fname];
downloadDirectory = tbxMainDownloadPath.Text;
downloadDirectory = Path.Combine(downloadDirectory, countryName);
}
else
{
fname = "Tempfile";
downloadDirectory = tbxMainDownloadPath.Text;
}
client.DownloadFileAsync(new Uri(url), downloadDirectory + "\\" + fname + ".gif");
lastDownloadedFile = downloadDirectory + "\\" + fname + ".gif";
label4.Text = downloadDirectory + "\\" + fname + ".gif";
return;
}
// End of the download
label2.Text = "All files have been downloaded";
}
private void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
// handle error scenario
throw e.Error;
}
if (e.Cancelled)
{
// handle cancelled scenario
}
if (url.Contains("animated") && url.Contains("infra"))
{
Image img = new Bitmap(lastDownloadedFile);
Image[] frames = GetFramesFromAnimatedGIF(img);
foreach (Image image in frames)
{
countFrames++;
image.Save(downloadDirectory + "\\" + fname + ".gif");
}
}
label2.Text = "Download Complete";
tracker.NewFile();
DownloadFile();
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
tracker.SetProgress(e.BytesReceived, e.TotalBytesToReceive);
pBarFileProgress.Value = (int)(tracker.GetProgress() * 100.0);
label3.Text = e.BytesReceived + "/" + e.TotalBytesToReceive;
label7.Text = tracker.GetBytesPerSecondString();
label2.Text = "Downloading";
}
The start download button
private void btnStart_Click(object sender, EventArgs e)
{
downloadFile(lines);
}
Now I'm changing the labels visible property to true when I click the download button. But then the I see labels for some seconds before it's getting to the progressChanged event and update the labels.
The question is where should I change the visible to true of this labels 2,3,4,7 and that it will change it once to true ?
If you're concerned about showing the labels before you actually set any text to them, you should just make sure to set text to them before you get the progress changed event - e.g.
label3.Text = "0/calculating...";
label7.Text = "0 kbps";
label2.Text = "Preparing for download...";
in your downloadFiles method (before or after setting .Visible to true). On another note - pick better names for your labels! label3 might be better as something like lblTotalDownloaded, or label7 as lblDownloadSpeed, etc.
Related
Introduction:
Hello, I tried doing a program with a WinForms Application that downloads specific .zip files, but I get these errors:
UI look like
Errors what I get
Code:
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.Collections;
using System.Net;
using System.Threading;
namespace Universal_Installer
{
public partial class Form1 : Form
{
WebClient wc;
public Form1()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
FolderBrowserDialog def = new FolderBrowserDialog();
def.RootFolder = Environment.SpecialFolder.Desktop;
def.Description = "Select installation location...";
def.ShowNewFolderButton = true;
if (def.ShowDialog() == DialogResult.OK)
{
textBox1.Text = def.SelectedPath;
}
}
private void Button2_Click(object sender, EventArgs e)
{
if (!Directory.Exists(textBox1.Text))
{
MessageBox.Show("The selected path does not exist!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else if (Directory.Exists(textBox1.Text))
{
string inst_size = "n/a";
string name = "n/a";
bool able = false;
string downloadlink = "n/a";
string PeoplePlaygroundSize = "0.161";
string PrisonArchitectSize = "0.586";
string AnotherBrickInTheMallSize = "0.164";
if (PP.Checked == true)
{
inst_size = PeoplePlaygroundSize;
downloadlink = "(A download link)";
name = "People Playground.zip";
able = true;
}
else if (PA.Checked == true)
{
inst_size = PrisonArchitectSize;
downloadlink = "(A download link)";
name = "Prison Architect.zip";
able = true;
}
else if (ABITM.Checked == true)
{
inst_size = AnotherBrickInTheMallSize;
downloadlink = "(A download link)";
name = "Another Brick In The Mall.zip";
able = true;
}
if (able == false)
{
MessageBox.Show("No checkboxes are checked!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else if (MessageBox.Show("Are you sure you want to install a " + inst_size + " GB game?", "Are you sure?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
status.Text = "Status: DOWNLOADING (" + inst_size + " GB)";
//////
ABITM.Enabled = false;
PP.Enabled = false;
PA.Enabled = false;
textBox1.Enabled = false;
button1.Enabled = false;
button2.Enabled = false;
//////
Thread thread = new Thread(() =>
{
Uri uri = new Uri(downloadlink);
string filename = System.IO.Path.GetFileName(uri.AbsolutePath);
wc.DownloadFileAsync(uri, textBox1.Text + "/" + filename);
});
thread.Start();
}
}
}
private void FileDownloadComplete(object sender,AsyncCompletedEventArgs e)
{
status.Text = "Status: IDLE";
PBAR.Value = 0;
MessageBox.Show("Download Completed (PATH: "+textBox1.Text+")", "Finished", MessageBoxButtons.OK, MessageBoxIcon.Information);
ABITM.Enabled = true;
PP.Enabled = true;
PA.Enabled = true;
textBox1.Enabled = true;
button1.Enabled = true;
button2.Enabled = true;
}
private void Form1_Load(object sender, EventArgs e)
{
wc = new WebClient();
wc.DownloadProgressChanged += wc_DownloadProgressChanged;
wc.DownloadFileCompleted += FileDownloadComplete;
}
private void wc_DownloadProgressChanged(object sender, AsyncCompletedEventArgs e)
{
Invoke(new MethodInvoker(delegate ()
{
PBAR.Minimum = 0;
double recive = double.Parse(e.BytesReceived.ToString());
double total = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = recive / total * 100;
PBAR.Value = int.Parse(Math.Truncate(percentage).ToString());
}));
}
}
}
Help:
Any help? By the way, if you see any text ending with .Text or .Value etc... these mean they are objects.
I really need your help by the way...
According the Official Documentation, the second argument for the DownloadProgressChanged must be DownloadProgressChangedEventArgs instead of AsyncCompletedEventArgs.
private void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
Invoke(new MethodInvoker(delegate ()
{
PBAR.Minimum = 0;
double recive = double.Parse(e.BytesReceived.ToString());
double total = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = recive / total * 100;
PBAR.Value = int.Parse(Math.Truncate(percentage).ToString());
}));
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
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.Xml.Linq;
using System.Diagnostics;
using System.Management;
using System.Runtime.InteropServices;
namespace DownloadFiles
{
public partial class Form1 : Form
{
Stopwatch sw = new Stopwatch();
Stopwatch stopwatch = new Stopwatch();
string filesdirectory = "Downloaded_Files";
string mainurl = "http://www.usgodae.org/ftp/outgoing/fnmoc/models/navgem_0.5/latest_data/";
List<string> parsedlinks = new List<string>();
string path_exe = Path.GetDirectoryName(Application.LocalUserAppDataPath);
List<string> results = new List<string>();
List<string> urls = new List<string>();
string radarImageWebAddressP1;
string radarImageWebAddressP2;
public Form1()
{
InitializeComponent();
label3.Text = "";
label4.Text = "";
label5.Text = "";
label7.Text = "";
button2.Enabled = false;
button3.Enabled = false;
filesdirectory = Path.Combine(path_exe, filesdirectory);
if (!Directory.Exists(filesdirectory))
{
Directory.CreateDirectory(filesdirectory);
}
else
{
if (IsDirectoryEmpty(filesdirectory) == false)
{
button3.Enabled = true;
}
}
radarImageWebAddressP1 = "http://www.ims.gov.il/Ims/Pages/RadarImage.aspx?Row=";
radarImageWebAddressP2 = "&TotalImages=10&LangID=1&Location=";
for (int i = 0; i < 9; i++)
{
urls.Add(radarImageWebAddressP1 + i + radarImageWebAddressP2);
}
}
public bool IsDirectoryEmpty(string path)
{
return !Directory.EnumerateFileSystemEntries(path).Any();
}
private string downloadhtml(string url)
{
backgroundWorker1.ReportProgress(0, "Downloading Main Url");
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
request.Proxy = null;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream());
string html = sr.ReadToEnd();
sr.Close();
response.Close();
StreamWriter w = new StreamWriter(path_exe + "\\page.html");
w.Write(html);
w.Close();
return html;
}
int Counter = 0;
int percentage = 0;
int total = 0;
int countfiletodownload = 0;
bool processStatus = false;
private void Parseanddownloadfiles()
{
//downloadhtml(mainurl);
if (bgw.CancellationPending == false)
{
/*backgroundWorker1.ReportProgress(0, "Parsing Links");
HtmlAgilityPack.HtmlWeb hw = new HtmlAgilityPack.HtmlWeb();
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc = hw.Load(path_exe + "\\page.html");
foreach (HtmlAgilityPack.HtmlNode link in doc.DocumentNode.SelectNodes("//a[#href]"))
{
string hrefValue = link.GetAttributeValue("href", string.Empty);
if (hrefValue.Contains("US"))
{
string url = "http://www.usgodae.org/ftp/outgoing/fnmoc/models/navgem_0.5/latest_data/" + hrefValue;
parsedlinks.Add(url);
if (bgw.CancellationPending == true)
return;
}
}*/
parsedlinks = urls;
countfiletodownload = parsedlinks.Count;
total = parsedlinks.Count;
backgroundWorker1.ReportProgress(0, "Downloading Files");
processStatus = true;
for (int i = 0; i < parsedlinks.Count && bgw.CancellationPending == false; i++)
{
try
{
using (WebClient client = new WebClient())
{
sw.Start();
Uri uri = new Uri(parsedlinks[i]);
string filename = "RadarImage" + i.ToString() + ".gif";//parsedlinks[i].Substring(71);
client.DownloadFileAsync(uri, filesdirectory + "\\" + filename);
Counter += 1;
percentage = Counter * 100 / total;
string filenametoreport = filename.Substring(1);
countfiletodownload--;
backgroundWorker1.ReportProgress(percentage, filenametoreport);//countfiletodownload, filenametoreport);
}
}
catch (Exception err)
{
string error = err.ToString();
}
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
BackgroundWorker bgw;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
bgw = (BackgroundWorker)sender;
if (bgw.CancellationPending == true)
{
return;
}
else
{
Parseanddownloadfiles();
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.UserState.ToString() == "Downloading Main Url")
{
label3.Text = e.UserState.ToString();
}
if (e.UserState.ToString() == "Parsing Links")
{
label3.Text = e.UserState.ToString();
}
if (e.UserState.ToString() == "Downloading Files")
{
label7.Text = countfiletodownload.ToString();//parsedlinks.Count.ToString();
label3.Text = e.UserState.ToString();
}
if (processStatus == true)
{
if (e.UserState.ToString() != "Downloading Files")
{
label4.Text = e.UserState.ToString();
label7.Text = countfiletodownload.ToString();
progressBar1.Value = e.ProgressPercentage;
/*using (var bitmap = new Bitmap(this.Width, this.Height))
{
this.DrawToBitmap(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height));
bitmap.Save(#"e:\screens\ss.gif" + countscreenshots, System.Drawing.Imaging.ImageFormat.Gif);
countscreenshots += 1;
}*/
}
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
}
else
{
label3.Text = "Download Completed";
stopwatch.Reset();
stopwatch.Stop();
timer1.Stop();
}
if(e.Cancelled)
label3.Text = "Operation Cancelled";
button1.Enabled = true;
}
private void button2_Click(object sender, EventArgs e)
{
label3.Text = "Cancelling Operation";
backgroundWorker1.CancelAsync();
button2.Enabled = false;
timer1.Stop();
stopwatch.Stop();
stopwatch.Reset();
}
private void button1_Click(object sender, EventArgs e)
{
label3.Text = "";
label4.Text = "";
label7.Text = "";
backgroundWorker1.RunWorkerAsync();
timer1.Start();
stopwatch.Start();
button1.Enabled = false;
button2.Enabled = true;
}
private void button3_Click(object sender, EventArgs e)
{
Process.Start(filesdirectory);
}
private void timer1_Tick(object sender, EventArgs e)
{
label5.Text = string.Format("{0:hh\\:mm\\:ss}", stopwatch.Elapsed);
}
}
}
First time it's downloading fine but next time when clicking again the start button(button1) it's showing exception: System.Reflection.TargetInvocationException: 'Exception has been thrown by the target of an invocation.'
I tried to reset the progressBar value to 0 in the start button(button1) click event but it didn't solve the problem.
ArgumentOutOfRangeException: Value of '111' is not valid for 'Value'. 'Value' should be between 'minimum' and 'maximum'.
Parameter name: Value
The ArgumentOutOfRange exception is because you never reset Counter:
You define Counter as class level variable and initialize to 0:
int Counter = 0;
Then in your loop you call:
Counter += 1;
percentage = Counter * 100 / total;
When you click the button to restart the download, Counter still holds the final value of the previous run.
In button1_Click, prior to calling RunWorkerAsync
You need to reset it:
Counter = 0;
I'm doing two methods when searching. First retrieving files and then searching in the files.
But in some cases i change only the searching text i search for and i want to repeat the searching in the same directories and files. So how can i make that it will remember the last retrieved files ?
This is the button click event to start the backgorundworker and the searching methods:
private void startButton_Click(object sender, EventArgs e)
{
ListViewCostumControl.lvnf.Items.Clear();
numberoffiles = 0;
numberofrestrictedFiles = 0;
numberofdirs = 0;
label24.Text = "0";
label1.Text = "0";
label15.Text = "0";
Logger.Write("Operation started");
label21.Text = "Phase 1: Retrieving files";
label21.Visible = true;
startButton.Enabled = false;
stopButton.Enabled = true;
pauseresumeButton.Enabled = true;
label1.Select();
timer1.Start();
if (!backgroundWorker1.IsBusy)
{
SetWorkerMode(true);
backgroundWorker1.RunWorkerAsync();
}
}
This is the backgroundworker events in the completed i'm writing to a text file some information but not the whole retrieved files.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
_stopwatch.Restart();
string[] values = textBox1.Text.Split(new string[] { ",," }, StringSplitOptions.None);
DirSearch(textBox3.Text, textBox2.Text, values, worker, e);
_stopwatch.Stop();
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
MyProgress mypro = (MyProgress)e.UserState;
ListViewCostumControl.lvnf.Items.Add(mypro.Report1);
label15.Text = mypro.Report2;
label15.Visible = true;
if (ListViewCostumControl.lvnf.Items.Count > 9)
textBox4.Enabled = true;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
label1.Select();
_stopwatch.Stop();
label24.Text = "0";
label5.Text = "00:00:00";
label1.Text = "0";
label11.Text = "0";
label15.Text = "0";
label24.Text = "0";
pauseresumeButton.Enabled = false;
stopButton.Enabled = false;
startButton.Enabled = true;
timer1.Stop();
ListViewCostumControl.lvnf.Items.Clear();
Logger.Write("Operation cancelled");
button4.Enabled = true;
}
if (e.Error != null)
{
}
else
{
label1.Select();
_stopwatch.Stop();
timer1.Stop();
stopButton.Enabled = false;
pauseresumeButton.Enabled = false;
startButton.Enabled = true;
label21.Text = "Last operation ended at: " + DateTime.Now;
Logger.Write("Number of retrieved files: " + numberoffiles);
Logger.Write("Number of restricted files: " + numberofrestrictedFiles);
Logger.Write("Number of searched files: " + numberofdirs);
Logger.Write("Number of results: " + label15.Text);
Logger.Write("Searched root directory: " + textBox3.Text);
Logger.Write("Operation time: " + _stopwatch.Elapsed);
Logger.Write("Operation ended");
Logger.Write(" ");
button4.Enabled = true;
mCompleted = true;
if (mClosePending) this.Close();
}
}
This is the searching methods:
int numberofdirs = 0;
void DirSearch(string rootDirectory, string filesExtension, string[] textToSearch, BackgroundWorker worker, DoWorkEventArgs e)
{
List<string> resultsoftextfound = new List<string>();
List<string> resultsoftextfound1 = new List<string>();
List<string> filePathList = new List<string>();
int numberoffiles = 0;
try
{
filePathList = SearchAccessibleFilesNoDistinct(rootDirectory, null,worker,e).ToList();
}
catch (Exception err)
{
string ad = err.ToString();
}
label21.Invoke((MethodInvoker)delegate
{
label21.Text = "Phase 2: Searching in files";
});
MyProgress myp = new MyProgress();
myp.Report4 = filePathList.Count.ToString();
foreach (string file in filePathList)
{
try
{
_busy.WaitOne();
if (worker.CancellationPending == true)
{
e.Cancel = true;
return;
}
bool reportedFile = false;
for (int i = 0; i < textToSearch.Length; i++)
{
if (File.ReadAllText(file).IndexOf(textToSearch[i], StringComparison.InvariantCultureIgnoreCase) >= 0)
{
resultsoftextfound.Add(file + " " + textToSearch[i]);
if (!reportedFile)
{
numberoffiles++;
myp.Report1 = file;
myp.Report2 = numberoffiles.ToString();
myp.Report3 = textToSearch[i];
backgroundWorker1.ReportProgress(0, myp);
reportedFile = true;
}
}
}
numberofdirs++;
label1.Invoke((MethodInvoker)delegate
{
label1.Text = string.Format("{0}/{1}", numberofdirs, myp.Report4);
label1.Visible = true;
});
}
catch (Exception)
{
}
}
}
And SearchAccessibleFilesNoDistinct method:
string restrictedFile = "";
List<string> restrictedFiles = new List<string>();
int numberofrestrictedFiles = 0;
int numberoffiles = 0;
IEnumerable<string> SearchAccessibleFilesNoDistinct(string root, List<string> files,BackgroundWorker worker, DoWorkEventArgs e)
{
_busy.WaitOne();
if (files == null)
files = new List<string>();
if (Directory.Exists(root))
{
foreach (var file in Directory.EnumerateFiles(root))
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
return files;
}
restrictedFile = file;
string ext = Path.GetExtension(file);
if (!files.Contains(file) && ext == textBox2.Text)
{
files.Add(file);
}
numberoffiles++;
label24.Invoke((MethodInvoker)delegate
{
label24.Text = numberoffiles.ToString();
label24.Visible = true;
});
}
foreach (var subDir in Directory.EnumerateDirectories(root))
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
return files;
}
try
{
SearchAccessibleFilesNoDistinct(subDir, files,worker, e);
}
catch (UnauthorizedAccessException)
{
restrictedFiles.Add(restrictedFile);
numberofrestrictedFiles++;
label11.Invoke((MethodInvoker)delegate
{
label11.Text = numberofrestrictedFiles.ToString();
label11.Visible = true;
});
continue;
}
}
}
return files;
}
The idea is to give the user and option to choose if to save or not somehow the last retrieved files so when he repeat the searching it will not retrieve the whole files over again only will search in them. In other words if i repeat the last searching just make the second method.
I call it Phase 1 and Phase 2.
The problem might be that if i save the last retrieved files to a text files or something like that it might be a large file on the hard disk ?
Another problem is when i type the text to search for in textBox1 if i type two words with a space it's not the same without a space for example: Form1 is not the same as Form 1 How can i make that it will search for both results Form1 and Form 1 ?
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (textBox1.Text != "" && textBox3.Text != "" && Directory.Exists(textBox3.Text))
{
startButton.Enabled = true;
Properties.Settings.Default["Setting2"] = textBox1.Text;
Properties.Settings.Default.Save();
}
else
{
startButton.Enabled = false;
}
}
I did that if the user type in the textBox1 ,,
It will consider the text after it as another search text.
void lvnf_SelectedIndexChanged(object sender, EventArgs e)
{
if (ListViewCostumControl.lvnf.SelectedItems.Count > 0)
{
results = new List<int>();
richTextBox1.Text = File.ReadAllText(ListViewCostumControl.lvnf.Items[ListViewCostumControl.lvnf.SelectedIndices[0]].Text);
FileInfo fi = new FileInfo(ListViewCostumControl.lvnf.Items[ListViewCostumControl.lvnf.SelectedIndices[0]].Text);
label17.Text = ExtensionMethods.ToFileSize(fi.Length);
label17.Visible = true;
filePath = Path.GetDirectoryName(fi.FullName);
string word = textBox1.Text;
string[] test = word.Split(new string[] { ",," }, StringSplitOptions.None);
foreach (string myword in test)
{
HighlightPhrase(richTextBox1, myword, Color.Yellow);
label16.Text = results.Count.ToString();
label16.Visible = true;
if (results.Count > 0)
{
numericUpDown1.Maximum = results.Count;
numericUpDown1.Enabled = true;
richTextBox1.SelectionStart = results[(int)numericUpDown1.Value - 1];
richTextBox1.ScrollToCaret();
}
}
}
}
For example if i type to search for Form1,,Form 1
Then it will search for all the results of Form1 and of Form 1
Or if i type Form1,,Help
Then the results will be also for Form1 and for Help.
The question not sure if a problem is more logic. When i type only Form1 should i consider it somehow also as Form 1 or i should leave it as it is now Form1,,Form 1 ?
Before i searched for SwitchCameras and it found results but before that i searched for Switch Cameras and it didn't find any results and i didn't put ,, between the Switch Cameras.
So i think by logic Switch Cameras should also find SwitchCameras.
So how can i change this searching rule so if there is no ,, but there is a space between the words search also for one word ?
Switch Cameras will also find SwitchCameras but Switch,,Cameras might find more results.
This question already has answers here:
WebClient multi file Downloader error
(3 answers)
How do I Async download multiple files using webclient, but one at a time?
(3 answers)
Closed 5 years ago.
The button click event for starting the download
private void btnStart_Click(object sender, EventArgs e)
{
downloadFile(links);
}
links is a List with some http links inside.
And the WebClient events
private void downloadFile(IEnumerable<string> urls)
{
foreach (var url in urls)
{
_downloadUrls.Enqueue(url);
}
// Starts the download
btnStart.Text = "Downloading...";
btnStart.Enabled = false;
pBarFileProgress.Visible = true;
DownloadFile();
label2.Visible = true;
label3.Visible = true;
label4.Visible = true;
label7.Visible = true;
label3.Text = "";
label7.Text = "";
label2.Text = "";
label4.Text = "";
}
private void DownloadFile()
{
if (_downloadUrls.Any())
{
client.DownloadProgressChanged += client_DownloadProgressChanged;
client.DownloadFileCompleted += client_DownloadFileCompleted;
url = _downloadUrls.Dequeue();
if (url.Contains("animated") && url.Contains("infra"))
{
string startTag = "animated/";
string endTag = "/infra";
int index = url.IndexOf(startTag);
int index1 = url.IndexOf(endTag);
fname = url.Substring(index + 9, index1 - index - 9);
var countryName = codeToFullNameMap[fname];
downloadDirectory = tbxMainDownloadPath.Text;
downloadDirectory = Path.Combine(downloadDirectory, countryName);
}
else
{
fname = "Tempfile";
downloadDirectory = tbxMainDownloadPath.Text;
}
client.DownloadFileAsync(new Uri(url), downloadDirectory + "\\" + fname + ".gif", url);
lastDownloadedFile = downloadDirectory + "\\" + fname + ".gif";
return;
}
// End of the download
label2.Text = "All files have been downloaded";
}
private void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Cancelled)
{
tracker.NewFile();
DownloadFile();
return;
// handle cancelled scenario
}
if (e.Error != null)
{
// handle error scenario
throw e.Error;
}
label2.Text = "Download Complete";
string lastUrl = (string)e.UserState;
listView1.BeginUpdate();
foreach (ListViewItem li in listView1.Items)
{
if (li.SubItems[2].Text == lastUrl)
{
li.SubItems[0].Text = "Downloaded";
li.SubItems.Add("Color");
li.SubItems[0].ForeColor = Color.Green;
li.UseItemStyleForSubItems = false;
}
}
listView1.EndUpdate();
tracker.NewFile();
DownloadFile();
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
tracker.SetProgress(e.BytesReceived, e.TotalBytesToReceive);
pBarFileProgress.Value = (int)(tracker.GetProgress() * 100.0);
label3.Text = e.BytesReceived + "/" + e.TotalBytesToReceive;
label7.Text = tracker.GetBytesPerSecondString();
label2.Text = "Downloading";
label4.Text = downloadDirectory + "\\" + fname + ".gif";
}
The exception is on line number 178
client.DownloadFileAsync(new Uri(url), downloadDirectory + "\\" + fname + ".gif", url);
And line 233 is in the completed event:
DownloadFile();
I tried to google in many answers it say that the download is not completed yet before running a new webclient request. I was sure if it's getting to the completed event that' mean the current download is finished no ?
How should i solve and handle this exception ?
The exception:
Blockquote
InnerException:
HResult=-2146233067
Message=WebClient does not support concurrent I/O operations.
Source=System
StackTrace:
at System.Net.WebClient.ClearWebClientState()
at System.Net.WebClient.DownloadFileAsync(Uri address, String fileName, Object userToken)
at DownloadMultipleFiles.Form1.DownloadFile() in Form1.cs:line 178
at DownloadMultipleFiles.Form1.client_DownloadFileCompleted(Object sender, AsyncCompletedEventArgs e) in Form1.cs:line 233
at System.ComponentModel.AsyncCompletedEventHandler.Invoke(Object sender, AsyncCompletedEventArgs e)
at System.Net.WebClient.OnDownloadFileCompleted(AsyncCompletedEventArgs e)
at System.Net.WebClient.DownloadFileOperationCompleted(Object arg)
InnerException:
call the wait Methode of
client.DownloadFileAsync(new Uri(url), downloadDirectory + "\\" + fname + ".gif", url).Wait();
Have a try
I have a button click event where I make once some Lists and start the backgroundworker1:
private void btnDownload_Click(object sender, EventArgs e)
{
btnDownload.Enabled = false;
label7.Text = "Downloading...";
ei.Init();
if (countryList.Count() == 0)
{
foreach (ExtractImages.Continent continent in ei.world.continents)
{
foreach (ExtractImages.Country country in continent.countries)
{
if (country.name == "Israel")
{
foreach (string imageUri in country.imageUrls)
{
countryList.Add(imageUri);
}
}
else
{
foreach (string imageUri in country.imageUrls)
{
newList.Add(imageUri);
}
}
}
}
}
backgroundWorker1.RunWorkerAsync();
}
In the dowork event:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
if (downloaded == false)
{
getTotalBytes(countryList);
CreateCountryDateTimeDirectories(countryList);
downloadFile(countryList);
}
else
{
getTotalBytes(newList);
CreateCountryDateTimeDirectories(newList);
downloadFile(newList);
}
}
In the dowork event I have two phases first it will make calculations and will download the links in the List countryList.
What I want to do is once it finish to download all the link in countryLinks start backgroundworker1 over again and this time download the links in the List newList.
This is how l'm downloading the links in the List.
private Queue<string> _downloadUrls = new Queue<string>();
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();
}
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), #"c:\temp\TempSatFiles\" + urlCount + "Infrared.jpg");
//await client.DownloadFileTaskAsync(new Uri(url), countriesMainPath + "\\" + currentDownloadCountry + "\\" + urlCount + "Infrared.jpg");
}
else
{
await client.DownloadFileTaskAsync(new Uri(url), #"c:\temp\TempSatFiles\" + urlCount + "Invisible.jpg");
//await client.DownloadFileTaskAsync(new Uri(url), countriesMainPath + "\\" + currentDownloadCountry + "\\" + urlCount + "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;
private async void Completed(object sender, AsyncCompletedEventArgs e)
{
var cnt = System.Threading.Interlocked.Decrement(ref urlCount);
if (cnt > 0)
{
await DownloadFile();
label9.Text = urlCount.ToString();
}
else
{
label7.Text = "Download completed";
downloaded = true;
btnDownload.Enabled = true;
sw.Stop();
}
}
Now it will download the links in countryList.
When it finish download all the files in the List it will get to the else part:
label7.Text = "Download completed";
downloaded = true;
btnDownload.Enabled = true;
sw.Stop();
Here i want to restart the backgroundworker1 and this time in the dowork event it will download the links in the newList.
The problem is how do I know that the backgroundworker1 is not busy ? There might be a situation that it downloaded the all the files and the backgroundworker1 is still busy ?
Or maybe I should start the backgroundworker in the completed event of the backgroundworker ? If it finished all the downloads it will then get to the backgroundworker completed event ? or first it will get to the webclient completed event ?
You can check if the worker is busy or not by using...
if(!backgroundworker1 .IsBusy)
backgroundworker1 .RunWorkerAsync();
No, if you've properly checked when it finishes then the worker will finish on when the downloading completes, it can be busy when it will wait for response and the response doesn't come soon.
Yes, when worker completes it work, it is recommended(from my side) to start it again to perform some other tasks.
Yes whenever it will finish, the completed event will be fired.
the event of webclient is inside the backgroundworker event, webclient completed event will be first. You've to debug your code first to see the sequential flow of your code.