How Do I Show Image Loading Progress in progress-bar c# - c#

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

Related

While Loop Locks UI Thread

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?

Can we call method in DoWork event?

I am exporting a Data Table to excel file using background worker. And I wanted to show the export progress using progress bar. Do we have to write the exporting code in Do Work event or can we call a method, which is present in other class.
In my code I tried calling different method. But its not working.
Below is the sample code.
public MainWindow()
{
InitializeComponent();
property = new Property();
this.DataContext = property;
worker.WorkerReportsProgress = true;
worker.DoWork += worker_DoWork;
worker.ProgressChanged += worker_ProgressChanged;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
System.Windows.Forms.MessageBox.Show(e.Error.Message);
}
else
{
System.Windows.Forms.MessageBox.Show("Exported Successfully");
}
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pbStatus.Value = e.ProgressPercentage;
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
Export export = new Export();
export.GenerateExcelFile();
}
You need to call worker.ReportProgress from worker_DoWork with a valid progress value
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
worker.ReportProgress(0);
// Some job
worker.ReportProgress(10);
// ...
// Finish
worker.ReportProgress(100);
}
I'm not sure how you are generating report. Further I'm supposing your pbStatus has Minimum="0" and Maximum="100". You can after exporting each row report progress something like that.
worker.ReportProgress(currentRow * 100.0 / totalRows);
You also set your progress bar intermediate if you are not sure how to calculate that by setting progress.IsIndeterminate to true
pbStatus.IsIndeterminate = true;

Stopping application from not displaying because of form_load code

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.

Progress bar is not working correctly

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

Change Backgroundworker Progress from other function

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.

Categories

Resources