2

I have a few nested for loops, and I was wondering if I could get the data while it's processing it, So I can show it on the screen as a loading bar.

Here's an example:

double currentData;
double endData = 50 * 50 * 50;

for(int i = 0; i < 50; i++)
{
  for(int e = 0; e < 50; e++)
  {
    for(int a = 0; a < 50; a++)
    {
      currentData = a * e * i;
    }
  }  
}

label1.Text = "Loading: " + Convert.ToString(100/endData * currentData) + "%.";

If I'm not wrong, for loops make the program "freeze" until its done, so that's probably why this code won't work. Any suggestions?

Thanks

TheVillageIdiot
  • 40,053
  • 20
  • 133
  • 188
Nick Peelman
  • 585
  • 1
  • 10
  • 28
  • is `for(int a : 0; a < 50; a++)` a typo? – Matt Busche Sep 02 '13 at 23:05
  • You can put your `label1.Text = ` line inside the loops, and call `Application.DoEvents` directly after it. Or look up `BackgroundWorker` and use it to do the work in a background thread. – Blorgbeard Sep 02 '13 at 23:10

3 Answers3

5

Well if you are using WinForms you can use background worker to execute the loop:

//declare in form
var bw = new BackgroundWorker();

//in constructor or load write this
bw.WorkerReportsProgress = true;
bw.DoWork += new DoWorkEventHandler(bwDoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bwProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwCompleted);

private void bwDoWork(object sender, DoWorkEventArgs e)
{
    var worker = sender as BackgroundWorker;
    for(int i = 0; i < 50; i++)
    {
        for(int e = 0; e < 50; e++)
        {
            for(int a : 0; a < 50; a++)
            {
                worker.ReportProgress(a * e * i);
            }
        }  
    }
}

private void bwProgressChanged(object sender, ProgressChangedEventArgs e)
{
    var pp=e.ProgressPercentage; //now set the progress here
}

private void bwCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    //set the progress to 100% etc.
}

Then as pointed by @paqogomez you need to call the worker to run, may be on some button click etc.

//may be in private void button_click(object sender, EventArgs e)
if (!bw.IsBusy)
{
    bw.RunWorkerAsync();
}

You can get more info on BackgroundWorker here and here.

TheVillageIdiot
  • 40,053
  • 20
  • 133
  • 188
3

Your supposition is right, try to update label1.Text inside your for-loop if you want to see it change.

pinckerman
  • 4,115
  • 6
  • 33
  • 42
  • 2
    You won't actually see anything unless you also call `Application.DoEvents`. – Blorgbeard Sep 02 '13 at 23:10
  • Oh. That makes so much sense... Thanks ! EDIT: `Application.DoEvents`? – Nick Peelman Sep 02 '13 at 23:10
  • Well it's not so so right, the program don't freeze, it just completes the loops before updating the label – Simon Rapilly Sep 02 '13 at 23:11
  • 2
    @NickPeelman normally while the `for` loops are executing, that is all the program is doing: it's not even doing stuff like repainting the screen. `Application.DoEvents` tells it to take a few milliseconds to handle move/resize/repaint/etc work. – Blorgbeard Sep 02 '13 at 23:13
  • @SimonRapilly he wrote "freeze" in quotes, I think he didn't mean it literally. – pinckerman Sep 02 '13 at 23:14
  • #Blorgbear ooh, but that'll make it load slower probably, but at least you can see what's happening now – Nick Peelman Sep 02 '13 at 23:14
  • Correct, it will be slower. The better option is to use a different thread, as per @dasblinkenlight's answer. – Blorgbeard Sep 02 '13 at 23:15
1

If I'm not wrong, for loops make the program "freeze" until its done, so that's probably why this code won't work.

You are absolutely right: if you run your loop on the UI thread, the UI is not going to update until the loop is done, so this approach is not viable.

Any suggestions?

You need to do the work in a background thread, and update the progressBar as you go. You wouldn't be able to set the value directly from a different thread, so you would need to use a delegate and a special dispatch mechanism. Here is an answer that shows how this is done in WPF and Windows Forms.

Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523