I have two forms, a main form that takes in parameters and a progress bar form that shows the progress of the time-consuming work.
A problem I'm having right now is that the BackgroundWorker is not reporting progress in order, which makes the progress bar look weird and not accurate.
I'm new to winforms so I don't know if this has to do with the way how I set up my forms.
The main form has a "Copy" button which starts the process (ProgressBarForm takes in backgroundWorker1 because I have a cancel button on the form):
private void copyButton_Click(object sender, EventArgs e)
{
if (!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync();
}
progBarForm = new ProgressBarForm(backgroundWorker1);
progBarForm.ShowDialog();
}
my DoWork looks like this:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (progBarForm == null)
{
// wait
}
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
}
else
{
startCopy(e);
}
}
StartCopy (some lines are omitted, but the structure is the same):
private void startCopy(DoWorkEventArgs e)
{
List<string> names = readExcelFile(excelPath);
// update progress bar max
progBarObj.max = names.Count();
progBarObj.action = (int) ProgObjAction.updateMax;
backgroundWorker1.ReportProgress(0, progBarObj);
foreach (string name in names)
{
if (backgroundWorker1.CancellationPending)
{
// if cancel button is clicked, cancel the work
e.Cancel = true;
return;
}
// update progress bar label
progBarObj.name = name;
progBarObj.action = (int)ProgObjAction.updateName;
backgroundWorker1.ReportProgress(0, progBarObj);
// where time-consuming work is being done
copyFile(name, e);
// perform progress bar step
progBarObj.action = (int)ProgObjAction.step;
backgroundWorker1.ReportProgress(0, progBarObj);
}
}
ProgBarObj is a struct that stores update info, and ProgObjAction is just an enumeration. copyFile function also calls ReportProgress.
ProgressChanged looks like this:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ProgObj progObj = (ProgObj)e.UserState;
switch (progBarObj.action)
{
case (int)ProgObjAction.updateName:
progBarForm.updateLabel(progObj.name);
break;
case (int)ProgObjAction.updateMax:
progBarForm.updateMax(progObj.max);
break;
case (int)ProgObjAction.step:
progBarForm.performStep();
break;
}
}
Within the ProgressBarForm I have functions that update the label, progress bar maximum and perform step.
I did some research and found out that BackgroundWorker ProgressChanged won't execute in order if it's a console app, but this is not my case here. ProgressChanged also runs on the main thread. So I really don't understand what's going on.
Any help would be appreciated!
Related
I've got one form called Sorter. There is the button 'jademy' on it which opens window 'Progress Window'
private void jademy_Click(object sender, EventArgs e)
{
ProgressWindow progress = new ProgressWindow();
progress.ShowDialog();
}
Code of 'Progress Window' form is following:
public partial class ProgressWindow : Form
{
private BackgroundWorker backgroundWorker = new BackgroundWorker();
public ProgressWindow()
{
InitializeComponent();
stop.Visible = true;
ok.Visible = false;
backgroundWorker.RunWorkerAsync();
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.WorkerSupportsCancellation = true;
#region block1
backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
#endregion
}
private void stop_Click(object sender, EventArgs e)
{
backgroundWorker.CancelAsync();
}
private void ok_Click(object sender, EventArgs e)
{
this.Close();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= 100; i++)
{
Thread.Sleep(100);
backgroundWorker.ReportProgress(i);
}
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
this.Text = "Done: " + e.ProgressPercentage.ToString() + "%";
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if ((e.Cancelled == true))
{
MessageBox.Show("Cancelled", "Message", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk);
}
else if (!(e.Error == null))
{
MessageBox.Show("Error: " + e.Error.Message, "ERROR!", MessageBoxButtons.OKCancel);
}
else
{
ok.Visible = true;
stop.Visible = false;
}
}
}
Now. I have three problems.
Click on stop button does nothing. It seems that 'backgroundWorker.CancelAsync()' doesn't stop the process.
When I close progress window and I want to run it again I have to wait some time before click on 'jademy' button. Otherwise progress window is displayed like this:
(and nothing changes) instead of this: It looks like the program "remembers" that work was done even though it is a new instance of ProgressWindow. Notice that on the incorrect version 'OK' button is visible at once - instead of waiting for the completion of the work.
I would like to clarify the code in "block 1". To be honest I don't understand it fully. Is this part really essential or not? I mean, I've found a lot of examples (also on this forum - e.g. here), where this part wasn't included and users were reporting that the solution works. In my case, without this part progress bar didn't work at all, but maybe I've done something wrong.
Calling CancelAsync stops any pending work. But if the work has already started, the method body needs to check if cancel was called. See CancelAsync
CancelAsync submits a request to terminate the pending background
operation and sets the CancellationPending property to true.
When you call CancelAsync, your worker method has an opportunity to
stop its execution and exit. The worker code should periodically check
the CancellationPending property to see if it has been set to true.
I have no idea about it. By the way the images do not work. Embed it in the question.
The code assigns a method that is executed when the BackgroundWorker starts and you hook up methods to report the progress and do cleanup / updates once the background work is complete.
BackgroundWorker.CancelAsync is often misunderstood. It does not stop any pending work but is merely a signal to the UI thread that the work has been canceled! It just sets the CancellationPending property, which you can poll in the DoWork regularly.
Unfortunately the MSDN example with the Thread.Sleep calls in the DoWork is a very silly one. Normally you call a blocking operation in DoWork, which is often completely UI-independent.
See my answer here for a more usable example.
1.
According to MSDN BackgroundWorker Class page, maybe you should add a break to the loop.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}
2.
Have no idea.
3.
The block 1 region is setting for BackgroundWorker event. In my case , it normally will appear at Form1.Designer.cs if I click the lightning icon in attribute to set the event.
I am using C# with WinForms. I am updating a progressBar. When the Value reaches it's maximum value, I would like it to display a messageBox.
Is there anyway for the progressBar to execute a method when it's full? Is so then some code sample or a link to the solution would be appreciated
private void BackgroundWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
{
//throw new NotImplementedException();
}
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
}
// Back on the 'UI' thread so we can update the progress bar - and our label :)
void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// The progress percentage is a property of e
int percentComplete = progressBarStatus.Value / progressBarStatus.Maximum;
labelPercentComplete.Text = percentComplete.ToString() + "% Completed";
//progressBarStatus.Value = e.ProgressPercentage;
//labelPercentComplete.Text = String.Format("Trade{0}", e.ProgressPercentage);
}
private void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(progressBarStatus.Value == progressBarStatus.Maximum)
{
MessageBox.Show("Test");
}
}
public void Form1_Load(object sender, EventArgs e)
{
backgroundWorker1.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler
(bgWorker_RunWorkerCompleted);
backgroundWorker1.ProgressChanged += BackgroundWorkerProgressChanged;
}
It appears that you do not want to do something when background worker completes, but you want to do something when progress bar reaches maximum... Ok, first, set your progressBarStatus maximum value, then you should try something like this:
void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (progressBarStatus.Maximum == e.ProgressPercentage)
{
// do whatever you want to do
}
}
and update progressBarStatus value from from another form.
Altough this may not the best way to do things, if this is really what you want, then do whatever makes you happy... :)
EDIT:
Ok, I added complete example of the program that works perfectly, with calling ProgressChanged event, and checking for the Maximum value correctly, when the Maximum value is reached, ProgressBar is getting restarted and the message is printed in the Output window, with bunch of comments (and bunch of typos of course :D ), please try this example, see how it works, and apply it to your problem.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace BGWORKERAPP
{
public partial class Form1 : Form
{
BackgroundWorker bgWorker = new BackgroundWorker();
public Form1()
{
InitializeComponent();
bgWorker.DoWork += bw_DoWork;
bgWorker.WorkerReportsProgress = true; // needed to be able to report progress
bgWorker.WorkerSupportsCancellation = true; // needed to be able to stop the thread using CancelAsync();
bgWorker.ProgressChanged += bw_ProgressChanged;
bgWorker.RunWorkerCompleted += bw_RunWorkerCompleted;
// ProgressBar is added to the form manually, and here I am just setting some initial values
progressBarStatus.Maximum = 100;
progressBarStatus.Minimum = 0;
progressBarStatus.Value = 0;
progressBarStatus.Step = 10;
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
int i = 0;
while (true) // keep looping until user presses the "Stop" button
{
if (bgWorker.CancellationPending) // if bgWorker.CancelAsync() is called, this CancelationPending token will be set,
{ // and if statement will be true
bgWorker.CancelAsync();
return; // Thread is getting canceled, RunWorkerCompleted will be called next
}
i++; // add any value you want, I chose this value because of the test example...
Thread.Sleep(1); // give thread some time to report (1ms is enough for this example) - NECESSARY,
//WITHOUT THIS LINE, THE MAIN THREAD WILL BE BLOCKED!
bgWorker.ReportProgress(i); // report progress (will call bw_ProgressChanged) - NECESSARY TO REPORT PROGRESS!
}
}
int somethingTerrible = 1; // used to do something terrible ;)
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// I added this "somethingTerrible" variable to make the ProgressChanged run all over again, even when e.ProgressPercentage value
// is greater then the progressBarStatus.Maximum, but, you should call bw.CancelAsync() because the job should be finished.
// Also, this code will give you Exception eventually, numbers are limited after all...
if (somethingTerrible * progressBarStatus.Maximum == e.ProgressPercentage)
{
Debug.WriteLine("THIS IS CALLED WHEN THE MAXIMUM IS REACHED"); // this will be printed in the Output window
progressBarStatus.Value = 0; // progressBarStatus value is at the maximum, restart it (or Exception will be thrown)
//bw.CancelAsync(); // used to stop the thread when e.ProgressPercentage is equal to progressBarMaximum, but in our
// example, we just make the code keep running.
// We should cancel bgWorker now because the work is completed and e.ProgressPercentage will
// be greater then the value of the progressBarStatus.Maximum, but if you really want
// you can do something like this to make the thread keep reporting without any errors (until numbers reach the limit)...
somethingTerrible++;
}
else
{
progressBarStatus.Value++; // increasing progressBarStatus.Value, until we get to the maximum.
}
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Worker completed"); // worker finished the task...
}
// Buttons are added to the Form manually as well
private void runBgTask_Click(object sender, EventArgs e) // button on the Form to start the thread
{
bgWorker.RunWorkerAsync(); // start the background worker (call DoWork)
}
private void stopBgTask_Click(object sender, EventArgs e) // button on the Form to stop the thread
{
bgWorker.CancelAsync(); // tell the background worker to stop (will NOT stop the thread immediately); the DoWork will be
// called once again, but with CancelationPending token set to true, so the if statement
// in the DoWork will be true and the thread will stop.
}
}
}
I guess you should look at BackgroundWorker which is made specifically for this purpose. You will get Event RunWorkerCompleted when your work in finished. I am giving you a working example where you are copying lots of files.
BackgroundWorker bgWorker = new BackgroundWorker();
bgWorker.DoWork += BackgroundWorkerDoWork;
bgWorker.ProgressChanged += BackgroundWorkerProgressChanged;
bgWorker.RunWorkerCompleted += new BackgroundWorkerCompletedEventHandler
(bgWorker_RunWorkerCompleted);
void StartWork()
{
// Start BackGround Worker Thread
bgWorker.RunWorkerAsync();
}
void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
//NOTE : DONT play with the UI thread here...
// Do Whatever work you are doing and for which you need to show progress bar
CopyLotsOfFiles() // This is the function which is being run in the background
e.Result = true;// Tell that you are done
}
void CopyLotsOfFiles()
{
Int32 counter = 0;
List<String> filestobeCopiedList = ...; // get List of files to be copied
foreach (var file in filestobeCopiedList)
{
counter++;
// Calculate percentage for Progress Bar
Int32 percentage = (counter * 100) / filesCount;
bgWorker.ReportProgress(percentage);
// Files copy code goes here
}
bgWorker.ReportProgress(100);
}
void BackgroundWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Access Main UI Thread here
progressBar1.Value = e.ProgressPercentage;
}
private void BackgroundWorkerCompletedEventHandler(object sender, RunWorkerCompletedEventArgs e)
{
//Always check e.Cancelled and e.Error before checking e.Result!
//even though I'm skipping that here
var operationSuccessFul = Convert.ToBoolean(e.Result);
if(operationSuccessFul)
MessageBox.Show("I am Done");
}
You will get a call in BackgroundWorkerCompletedEventHandler function when you are done. You should display your progress bar in BackgroundWorkerProgressChanged event handler
You should think the other way round: Create a central "Progress class". This class is responsible for:
Update the progress bar
Show a MessageBox if certain conditions are met
Or to put it another way: its not the responibility of the progressbar to ... do something else than showing progress.
I'm using a BackgroundWorker to periodically check a hardware switch. Due to it is connected via a slow RS485 network, I have to delay the next status update.
On switch Status change I want to update an OK/nOK Picture Box. This is realized as a green OK pictureBox over a nOK pictureBox. No real work is done here.
For expandability I decided to use the Backgroundworker. Finally I want to have a hidden worker, which
provides globally the Status of three switches and
updates on StatusChange the PictureBoxes.
Problem description
Once the BackgroundWorker is started, it works as expected. However the GUI freezes.
What did I try?
The MSDN BackgroundWorker Class Note 1
says, that GUI should be updated via ProgressChanged. I tried to raise this Event by Worker_Switch.ReportProgress(fakeProgress++) and failed. The PictureBox wasn't updated anymore.
Snippet from designer
this.Worker_Switch = new System.ComponentModel.BackgroundWorker();
//
// Worker_Switch
//
this.Worker_Switch.WorkerSupportsCancellation = true;
this.Worker_Switch.DoWork += new System.ComponentModel.DoWorkEventHandler(this.Worker_Switch_DoWork);
Snippet from Main Form
delegate void SetEventCallback(object sender, DoWorkEventArgs e); // Threadsafe calls for DoWork
private void btnBackgroundworker_Click(object sender, EventArgs e)
{
if (!Worker_Switch.IsBusy)
{
Worker_Switch.RunWorkerAsync();
}
}
private void Worker_Switch_DoWork(object sender, DoWorkEventArgs e)
{
// Worker Thread has no permission to change PictureBox "pictureBoxSwitchrightOK"
// Therefore this method calls itsself in the MainThread, if necessary.
while (!Worker_Switch.CancellationPending)
{
if (this.pictureBoxSwitchrightOK.InvokeRequired) // Worker Thread
{
System.Threading.Thread.Sleep(400);
SetEventCallback myCall = new SetEventCallback(Worker_Switch_DoWork);
this.Invoke(myCall, new object[] { sender, e });
}
else // Main Thread
{
// Turns OK Picture Box invisible, if nOk State (Switch pushed)
pictureBoxSwitchrightOK.Visible = SwitchOK("right"); // true: OK (green)
this.Refresh();
}
}
private bool SwitchOK(string rightOrLeft) // select one of the switches
{ (...)} // gets hardware switch status
Edit: Special Thanks to laszlokiss88 (3 possibilities) and JMK (for simplicity with System.Windows.Forms Timer from toolbox)
This alternative from Toolbox also worked:
this.timer_Switch.Enabled = true;
this.timer_Switch.Interval = 400;
this.timer_Switch.Tick += new System.EventHandler(this.timer_Switch_Tick);
private void timer_Switch_Tick(object sender, EventArgs e)
{
motorSwitchControl.Init(); // globally available Switch status
SwitchRight = SwitchOK("right");
SwitchRightOK.Visible = SwitchRight;
SwitchLeft = SwitchOK("left"); // globally available Switch status
SwitchLeftOK.Visible = SwitchLeft;
SwitchAllOK = SwitchRight & SwitchLeft;
this.Refresh();
}
a) Is it correct, that the Sleep() actually happens in the Worker Thread?
- no Main Thread
b) What is going wrong, if I manipulate user interface objects in DoWork? (Contrary to MSDN Note)
- works in Main Thread?
c) What is the correct way to periodically update a PictureBox? DoWork, ProgressChanged, RunWorkerCompleted...?
- Three possibilities from laszlokiss88 answer.
You can update the UI from the DoWork event via the Dispatcher, or Control.Begininvoke(winforms), or you can do it via the ProgressChanged event of the BackgroundWorker:
public MainWindow()
{
InitializeComponent();
var bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerAsync();
}
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// You are in the main thread
// Update the UI here
string data = (string)e.UserState;
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
// You are in a worker thread
(sender as BackgroundWorker).ReportProgress(0, "right");
}
For a start you should almost never have a need to put an active background thead to sleep. I am also not sure why you are constructing/defining the delegate this way, try some thing like
public delegate void UpdatePictureBox();
myDelegate = new UpdatePictureBox(UpdatePictureboxMethod);
then you have a method UpdatePictureBoxMethod
private void UpdatePictureBoxMethod()
{
this.pictureBox1.Image = Properties.Resources.SomeImage;
}
or something simalar, where you pass in the image to update to.
Alternatively you could use the (bgWorker as BackgroundWorker).ReportProgress(progress, object); method. So from the background thread you call
(bgWorker as BackgroundWorker).ReportProgress(progressBarValue, infoBall);
where here class IfoBall will hold all your important information
class InfoBall
{
public int nProgressBar { get; set; }
public int nMaxProgressBar { get; set; }
public Image image { get; set; }
}
then you can pass this object back to the UI thread and do your updates
void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// On UI thread.
InfoBall someBall = (InfoBall)e.UserState;
this.pictureBox1.Image = someBall.image;
// etc...
}
I hope this helps.
I am attempting to add a progress bar in my c# excel add in. The progress bar appears but it does not indicate any progress until the function is finished executing.
These are the functions in the Windows Form Class:
public void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 100; i++)
{
Thread.Sleep(100);
backgroundWorker1.ReportProgress(i); //run in back thread
}
}
public void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) //call back method
{
progressBar1.Value = e.ProgressPercentage;
}
public void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) //call back method
{
progressBar1.Value = progressBar1.Maximum;
}
This is how I call the function from the add in button:
private void buttonClicked(object sender, RibbonControlEventArgs e)
{
AddInPlanView.Form1 pBar = new AddInPlanView.Form1();
pBar.Visible = true;
pBar.backgroundWorker1.WorkerReportsProgress = true;
pBar.backgroundWorker1.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(pBar.backgroundWorker1_ProgressChanged);
pBar.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(pBar.backgroundWorker1_DoWork);
pBar.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(pBar.backgroundWorker1_RunWorkerCompleted);
pBar.backgroundWorker1.RunWorkerAsync();
FUNCTIONTORUN();
pBar.Visible = false;
}
How should I change this so that the progress bar will not stop working during the execution of FUNCTIONTORUN()? The progress bar is initialized using the Visual Studio designer. The name of the progressbar object in the form class is progressbar1.
Thank YOU!
The DoWork event for your progress bar should be (or contain) FUNCTIONTORUN(). FUNCTIONTORUN() should use the ReportProgress method.
What does FUNCTIONTORUN do? It is very likely blocking the UI thread, causing your updates to the progress bar to not be seen until it returns. More than likely, FUNCTIONTORUN needs to run in a background worker, and have it periodically report progress, and that's where you'd update the progress bar.
I would like to expand on the following statement. Matt Greer can correct me if I am wrong.
What does FUNCTIONTORUN do? It is very likely blocking the UI thread,
causing your updates to the progress bar to not be seen until it
returns. More than likely, FUNCTIONTORUN needs to run in a background
worker, and have it periodically report progress, and that's where
you'd update the progress bar.
What I believe he means by this is you need to update progressBar1.Value within
FUNCTIONTORUN(); you can still use a similar method.
I have question about progressbar show value.
I have this main thread
private void button1_Click(object sender, EventArgs e)
{
progress prog = new progress();
progress.progressEvent += new progress.progressEventHandler(progressEvent);
for(int i=0;i<100;i++)
{
Thread.Sleep(100);
prog.incA();
}
}
void progressEvent(object sender)
{
if (progressBar1.InvokeRequired)
{
//Tady mi to caka az kym nedobehne cyklus for a pak zacne tohleto fungovat
progressBar1.Invoke(new ChangeProgressBarValue(ProgressStep));
}
else
{
ProgressStep();
}
}
public void ProgressStep()
{
progressBar1.PerformStep();
}
public class progress
{
private ThreadStart ts;
private Thread th;
private bool status = true;
public delegate void progressEventHandler(object sender);
public static event progressEventHandler progressEvent;
private int b,a = 0;
public progress()
{
ts=new ThreadStart(go);
th = new Thread(ts);
th.IsBackground = true;
th.Start();
}
public void incA()
{
a++;
if(a==100)
status = false;
}
private void go()
{
while (status)
{
if (a != b)
{
b = a;
if (progressEvent != null)
progressEvent(this);
}
}
th.Abort();
}
}
and my problem is IF start main thread and call IncA this method call event and in event is progressbar invoke
and this invoke waiting to end main thread FOR
why waiting?
thx
Your loop in the main thread is preventing "paint" events from happening. Since you are calling your progress bar's function from withing that thread, you will never see the updates.
You need to move the code to do the incrementing to another thread entirely.
Here is a sample of what you want to do using a Button, a BackgroundWorker, and a ProgressBar:
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
for (int i = 1; i <= 100; i++)
{
backgroundWorker1.ReportProgress(i);
Thread.Sleep(100);
}
}
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
this.progressBar1.Value = e.ProgressPercentage;
}
Hope this helps!
The progress bar control is a UI object, and is created on the UI thread. When you call Invoke or BeginInvoke to update it, you are asking the UI thread to do the updating.
However, the UI thread is busy - in your button CLick event handler, you have a loop which Sleep()s the thread and calls prog.IncA in a loop. So it never exits back to the main UI loop (which is what dispatches windows messages and updates the UI). Your progress bar is being updated internally, but it never gets a chance to redraw because the UI thread is "busy".
The "processing" code (that is looping and calling prog.IncA()) should not be running on the UI thread at all - you need to start it off in a separate thread and then exit your Click handler so that the UI can continue to update.
Note that this has a side effect - if your UI thread is running, then the user will be able to continue interacting with your program, and so they can click again on the button and kick off another background thread - so you have to be very careful to make sure that the user can't do anything "dangerous" in the UI while you are busy processing.
I suggest you look at some introduction-to-threading tutorials to get an idea of how to use BackgroundWorker or another mechanism for running code in a separate thread. Once you understand that, you can add a progress bar. (And note that although a progress bar sounds like the simplest thing to do, it is actually rather a difficult thing to do due to the need for the UI thread to continue running but not let the user do anything dangerous during your processing)