Creating a .net application in C#, windows forms. How do I update the progress bar 1 step every cycle of a 100 cycle loop?
(I’m processing an excel sheet in the loop.)
The progress bar controls are in the UI class which connects to the controller class which connects to a custom class
(MVC pattern). The loop is in the custom class.
Do I need to send the UI class instance all the way down in each method or is there a better way?
Right now the progress bar updates after the loop finishes. Application.doevents and .update or .refresh don’t work.
Say the below is your class responsible for doing the work with the loop in it. Add an event to indicate your progress. Then from your UI simply handle that event and update the progress bar accordingly.
sealed class Looper
{
public event EventHandler ProgressUpdated;
private int _progress;
public int Progress
{
get { return _progress; }
private set
{
_progress = value;
OnProgressUpdated();
}
}
public void DoLoop()
{
_progress = 0;
for (int i = 0; i < 100; ++i)
{
Thread.Sleep(100);
Progress = i;
}
}
private void OnProgressUpdated()
{
EventHandler handler = ProgressUpdated;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
You might implement this by having a BackgroundWorker
as part of your UI, where in the backgroundWorker.DoWork
event you call looper.DoLoop()
. Then in your handler for the looper.ProgressUpdated
event you can call backgroundWorker.ReportProgress
to increment your progress bar from the UI thread.
Note that it would probably make more sense to include the progress itself in the information carried by your ProgressUpdated
event (I just didn't feel like writing out a new class deriving from EventArgs
to illustrate this; you probably get the picture anyway).
Also note that the above really doesn't make sense unless you're executing your code with the loop on a separate thread from the UI thread. Otherwise, all of your work is getting done before the next UI refresh anyway, so your progress bar would not be providing any value (it would just go from 0 to 100 when the loop completed).
Just an example of how this sort of thing can be achieved.
I usually have one class that does the invocation checks on the UI. UI -> "UpdaterClass" -> other class.
The Updater class has predefined methods and references to the UI controls. So Updater.StepProgressBar() is what I call to step the UI progress bar. I pass the Updater class reference to any class that is going to need to update the UI directly.
This way, all UI updates from different threads are handled by one class. Not the most generic way to impliment it, but it never fails.
Example psuedocode:
class Updater()
{
public ProgressBar pb;
delegate void UpdateProgressBar();
public StepProgressBar()
{
if(pb.InvokeRequired)
{
BeginInvoke(new UpdateProgressBar(this.StepProgressBar);
}
else
{
pb.Step();
}
}
}
Something like that.
You could use a delegate. When your background process creates the custom class, tie on a delegate that gets called from the custom class to report update. Then you can react to that call in the UI layer and update the progress bar from there.
e.g. (warning, psuedocode):
MyCustomClass class = new MyCustomClass();
class.ProgressUpdated += (s,e)=>{ /* update UI */};
class.StartLoop();