How do I update the progress bar one step, every l

2019-04-11 16:40发布

问题:

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.

回答1:

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.



回答2:

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.



回答3:

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();