I just tried to write code for a progress bar with webclient
Please see my code.
private void button2_Click(object sender, EventArgs e)
{
if (textBox1.Text == "")
{
MessageBox.Show("Invalid Php Url");
}
else if (Uri.IsWellFormedUriString(textBox1.Text, UriKind.Absolute) == false)
{
MessageBox.Show("Invalid Php Url");
}
else
{
backgroundWorker1.RunWorkerAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressCallback);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadFileCallBack2);
client.DownloadFile(textBox1.Text, #"D:\test\test.zip");
}
void DownloadProgressCallback(object sender, DownloadProgressChangedEventArgs e)
{
this.progressBar1.Value = e.ProgressPercentage;
this.label6.Text = e.ProgressPercentage.ToString();
}
void DownloadFileCallBack2(object sender, AsyncCompletedEventArgs c)
{
MessageBox.Show("Download Completed");
}
But the event is not calling why?
is this because of the background worker or any other issues?
Please help me.
Best regards,
I think it is because the progress updated is called on a background thread and not the UI thread. Try passing in the webclient to the DoWork thread:
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressCallback);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadFileCallBack2);
backgroundWorker1.RunWorkerAsync(client);
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
WebClient client = (WebClient)e.Argument;
client.DownloadFile(textBox1.Text, #"D:\test\test.zip");
}
Your Progress Bar must be of the following conditions :
-Accurate
-Responsive and smooth
-Precise
-Appropriate
Related
First I tried both :
DownloadProgressChangedEventHandler and AsyncCompletedEventHandler bit it didn't work.
Then I tried both :
client.DownloadProgressChanged += Client_DownloadProgressChanged;
client.DownloadFileCompleted += Client_DownloadFileCompleted;
This time it's getting right away to the completed event it's not downloading and not updating the progressBar1.
private void Download()
{
WebClient client = new WebClient();
string desktop = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
client.DownloadProgressChanged += Client_DownloadProgressChanged;
client.DownloadFileCompleted += Client_DownloadFileCompleted;
client.DownloadFileAsync(new Uri("https://speed.hetzner.de/10GB.bin"), desktop);
}
private void Client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
label1.Text = "Download Completed";
}
private void Client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar1.Maximum = (int)e.TotalBytesToReceive / 100;
progressBar1.Value = (int)e.BytesReceived / 100;
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar1.Maximum = (int)e.TotalBytesToReceive / 100;
progressBar1.Value = (int)e.BytesReceived / 100;
}
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
Download();
}
Declare the button1_Click and Download methods are async and add await before client.DownloadFileAsync.
Or you can use the synchronous version client.DownloadFile
I have a button in my WinForms application with the following Click event:
private void Button_Click(object sender, EventArgs e)
{
treasureFound = false;
refreshNumber = 0;
Label_StartDateTime.Text = DateTime.Now.ToString("dd-MM-yyyy HH:mm:ss");
while (!treasureFound)
{
Label_StatusData.Text = "Refreshed " + refreshNumber + " times.";
refreshNumber++;
using (WebClient client = new WebClient())
{
string htmlCode = client.DownloadString(webUrl);
if (htmlCode.Contains("Treasure"))
{
treasureFound = true;
Label_StatusData.Text = "Found.";
// etc etc
}
}
}
}
When the button is clicked, the UI thread locks up (not responding, labels don't update) until the while loop ends.
What can I do to keep the UI responsive? There should only be one WebClient instance at any one time.
you should execute the time-consuming tasks in a separate thread, so it will not block the main thread (aka your UI thread). One way is to use the BackgroundWorker.
public Form1()
{
InitializeComponent();
backgroundWorker1.DoWork += backgroundWorker1_DoWork;
backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
backgroundWorker1.WorkerReportsProgress = true;
}
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
for (int i = 0; i < 100; i++)
{
Thread.Sleep(1000);
backgroundWorker1.ReportProgress(i);
}
}
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
Taken from: How to use a BackgroundWorker?
I want to know how to show image loading progress in progress-bar in win form.
my code is
private void Form2_Load(object sender, EventArgs e)//load form and get profile and avatar
{
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
label2.Text = "Avatar Loaded";
}
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)//showing progress
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => backgroundWorker1_ProgressChanged(sender, e)));
}
else
{
if (progressBarX1.Value != e.ProgressPercentage)
{
progressBarX1.Value = e.ProgressPercentage;
progressBarX1.Refresh();
}
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)//loading avatar
{
WebClient wc = new WebClient();
Stream stream = wc.OpenRead("http://avatar.nimbuzz.com/getAvatar?jid=" + textBox1.Text);
pictureBox1.Image = (Image.FromStream(stream));
}
The image loads successfully but do not show any progress in progress-bar
Well, i would use the ProgressChanged Event from a WebClient to get the result of how far the download progress actually is. Then you can't save it from the thread of the backgroundworker, so you gotta do this when you have the file.
UPDATED
private BackgroundWorker bgw;
private void Form1_Load(object sender, EventArgs e)
{
bgw = new BackgroundWorker();
bgw.DoWork += bgw_DoWork;
bgw.WorkerReportsProgress = true;
bgw.RunWorkerCompleted += bgw_RunWorkerCompleted;
bgw.ProgressChanged += bgw_ProgressChanged;
bgw.RunWorkerAsync();
}
void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
pictureBox1.Image = (Image)e.Result;
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
WebClient wc = new WebClient();
wc.DownloadProgressChanged += wc_DownloadProgressChanged;
Stream stream = wc.OpenRead("" + textBox1.Text);
e.Result = (Image.FromStream(stream));
}
void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
bgw.ReportProgress(e.ProgressPercentage);
}
The problem with your code is that backgroundWorker1_ProgressChanged() is called in the context of the worker thread but UI updates can only be done within the UI thread (main thread). In your scenario you must call:
progressBarX1.Value = e.ProgressPercentage;
within the UI thread. There are many ways how to do this but a simple one is to use InvokeReqzired() to check if you are in the UI thread and you are not then call BeginInvoke() to send the execution of that command to the UI-/main-thread. The following should do the trick:
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => backgroundWorker1_ProgressChanged(sender, e)));
}
else
{
progressBarX1.Value = e.ProgressPercentage;
}
}
Update:
I would also change:
backgroundWorker1.RunWorkerAsync();
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
to:
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerAsync();
so the progress event is assigned (and therefore in place) before starting the asynchronous work. Otherwise you may miss a progress call.
Update 2:
You also need the following line to execute in the UI thread:
pictureBox1.Image = (Image.FromStream(stream));
To do so use the Completed event of BackgroundWorker and bass the image data using the result parameter. Then in the eventhandler use InvokeRequired() and BeginInvoke() just like in the Progress event).
Uodate 3:
Remeins unchanged is good as you don't get a crash because of not calling UI stuff in the UI thread ;-)
Try to force a repaint on the control by calling:
progressBarX1.Refresh();
(just after you assigned a new value to it).
So the code in the progress event looks like this:
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => backgroundWorker1_ProgressChanged(sender, e)));
}
else
{
if (progressBarX1.Value != e.ProgressPercentage)
{
progressBarX1.Value = e.ProgressPercentage;
progressBarX1.Refresh();
}
}
}
If that still doesn't work check that your main/UI thread is not blocked or totally busy.
Update 4:
Just to make sure: you need to enable progress-reporting on the background worker and call its ReportProgress() method from time to time within the backgroundWorker1_DoWork(). See the following MS-Tutorial for more information on usage of the BackgroundWorker: http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
Enabling progress reporting on a backgroundworker:
backgroundWorker1.WorkerReportsProgress = true;
or use the form-designer and set the property WorkerReportsProgress to True. Then you still need to call the backgroundWorker1.ReportProgress() from time to time.
Update 5:
Ok, lets give it a complete try. I've checked some reference docs from MS so in case of the backgroundworker ProgressChanged and Completed events you don't need to BeginInvoke() them as MS does this already for you.
private void Form2_Load(object sender, EventArgs e)
{
getto();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.ProgressChanged -= backgroundWorker1_ProgressChanged;
backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
backgroundWorker1.RunWorkerCompleted -= backgroundWorker1_Completed;
backgroundWorker1.RunWorkerCompleted += backgroundWorker1_Completed;
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
using (var wc = new WebClient())
{
wc.DownloadProgressChanged += (sender, e) => backgroundWorker1.ReportProgress(sender, e);
using (var stream = wc.OpenRead("http://avatar.nimbuzz.com/getAvatar?jid=" + textBox1.Text))
{
e.Result = (Image.FromStream(stream));
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
progressBarX1.Value = e.ProgressPercentage;
progressBarX1.Refresh();
}
private void backgroundWorker1_Completed(object sender, DoWorkEventArgs e)
{
pictureBox1.Image = e.Result;
}
How can I stop my application from not displaying until the form_load code is completed?
public partial class updater : Form
{
public updater()
{
InitializeComponent();
timer1.Interval = (10000) * (1);
progressBar1.Value = 0;
progressBar1.Maximum = 100;
progressBar1.Update();
timer1.Start();
}
private void updater_Load(object sender, EventArgs e)
{
WebClient webClient = new WebClient();
webClient.DownloadProgressChanged += webClient_DownloadProgressChanged;
webClient.DownloadFile("http://download827.mediafire.com/jl9c098fnedg/ncqun56uddq0y1d/Stephen+Swartz+-+Survivor+%28Feat+Chloe+Angelides%29.wav", Application.StartupPath + "\\Stephen Swartz - Survivor (Feat Chloe Angelides).wav");
// System.Diagnostics.Process.Start("\\Test.exe");
this.Close();
}
void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
progressBar1.Update();
}
}
If you use DownloadFileAsync it wont block the UI thread and will allow the Form to load and show the progress in the Progressbar, then you can use the DownloadFileCompleted event to close the Form
Example:
public Form1()
{
InitializeComponent();
progressBar1.Value = 0;
progressBar1.Maximum = 100;
progressBar1.Update();
}
private void updater_Load(object sender, EventArgs e)
{
WebClient webClient = new WebClient();
webClient.DownloadProgressChanged += webClient_DownloadProgressChanged;
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(webClient_DownloadFileCompleted);
webClient.DownloadFileAsync(new Uri("http://download827.mediafire.com/jl9c098fnedg/ncqun56uddq0y1d/Stephen+Swartz+-+Survivor+%28Feat+Chloe+Angelides%29.wav"), Application.StartupPath + "\\Stephen Swartz - Survivor (Feat Chloe Angelides).wav");
}
private void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
Close();
}
private void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
progressBar1.Update();
}
One way is to move your code from Load Shown Event. So the code will start runing after the form is shown.
The other is create a thread, where you will download a file.
For this purpose you can use BackgroundWorker
private void updater_Load(object sender, EventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (s, eArgs) =>
{
WebClient webClient = new WebClient();
webClient.DownloadFile("someUrl", "somePath");
};
worker.RunWorkerAsync();
}
Also there exists webClient.DownloadFileAsync method witch suits better in this situation. You can find description in sa_ddam213 answer.
I need to change my backgroundworker progress outside the DoWork Event is this possible ?
My code
private void progress_changed(string fileName, DownloadProgressChangedEventArgs e)
{
progress = e.ProgressPercentage;
Filename = fileName;
// change the progress here
}
private void worker_DoWork(string fileName)
{
WebClient client = new WebClient();
client.DownloadProgressChanged += (obj, e) => progress_changed(fileName, e);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(progress_complete);
client.DownloadFileAsync(new Uri(Link), Savepath);
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
mainForm.dlist.Items[mainForm.dlist.Items.IndexOfKey(Filename)].SubItems[2].Text = progress.ToString() + "%";
mainForm.dlist.Items[mainForm.dlist.Items.IndexOfKey(Filename)].SubItems[3].Text = "Downloading";
}
Pass the BackgroundWorker to the other function. From there, you can call ReportProgress. Alternatively, depending on your structure, you could make the BackgroundWorker a class field and access it that way.