3

Attempt number 2. Trying to be as clear as possible because I have been on this task for much longer than I should have and made little progress.

I need to make a progress bar for an application. Right now, everything is happening in one UI thread, all the processing and whatnot, so when I do the long running process after a click of a button, the program hangs for roughly 40 seconds, then resumes with the output (I cannot change that part, the application was given to me). And I also have to make a cancel button, so if it is hit during the intermediate process, after that process is done, it checks for the Cancel flag, and if it is ON, break out of all the methods and return to initial position.

What I have to do is make a progress bar for this process. Two of them, one for intermediate process and one for total. Intermediate is a small action, like DB call, output intermediate process (for and foreach loops).

I have tried putting the bars in the same UI window and update them in the same thread as I go on (find major points, start the progress bars there and increment them based on my judgement. And loops). That was just loading the UI even more, but it was working (choppy progress bar movements).

Then I tried using the background worker. Same thing, put the bars in the UI and run them through the background worker. The problem with that even though the BG worker runs, the refresh must happen in the UI window, which is busy processing the greedy request, so it is not updated when I want it to.

I tried using multi threading at core (no BG worker) and create a new form in a new thread that would reflect the progress, but I was cautioned not to do it (running 2 UI threads at the same time) and I had troubles passing values around. Not to mention if using the threading method it is impossible to get an accurate representation of the progress happening without completely overloading the CPU (have another thread run in a while(true) and do an update when you call the updateMethod from some point in the process)

Do I have any other options left? Because the least negative aspect is the first where I update the progress bar as I go along with the program.

Alexey
  • 3,607
  • 8
  • 34
  • 54
  • Why is your UI thread busy when you're doing the work in the BackgroundWorker? The whole *point* of the BGW is so that the UI *isn't* doing anything. The UI thread should start the BGW and then just be done while the BGW goes off to do it's own thing. Use the appropriate completed and updated events to update the UI with the progress and results of the background work. – Servy May 17 '13 at 18:55
  • @Serve I am using BGW to do the progress bar, not the UI. The main thread, which has the UI, is processing that long 40 seconds task. Putting all of into a BGW would mean rewriting half of the whole program. As I mentioned in the OP, it was presented to me like that. – Alexey May 17 '13 at 18:57
  • 1
    I have had that idea of doing the Apllication.DoEvents(), but it was frowned upon and referenced to as a "band aid to a bad design". – Alexey May 17 '13 at 18:58
  • 3
    @Alexey The progress bar *is* a part of the UI. If your UI thread is doing the processing and the background worker is updating the UI then you have it backwards, and you need to fix it. I don't see why it should take long; at some point there should just be one method that's starting all of the non-UI work. If there's not, extract it all into a method. Then just move that method from the event handler to the `DoWork` handler. Done. – Servy May 17 '13 at 18:59
  • What is the BGW for if the UI is processing the 40 second task? – LarsTech May 17 '13 at 19:00
  • It have never occurred to me that I can just put all of the processes in the BGW and free the UI. Can you post it as an answer? I will accept it. – Alexey May 17 '13 at 19:16

3 Answers3

3

Do I have any other options left? Yes and no. The best option is still to put time to learn how to use the backgroundworker properly, it's by far the easiest solution for this problem.

Go ahead and study these links:

Most important thing is to set this property:

bw.WorkerReportsProgress = true;

And in the DoWork-Function, make sure you report the progress to the UI, as given in the linked examples:

worker.ReportProgress((i * 10));

Also, don't forget to handle the progresschanged event in the UI:

private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    this.tbProgress.Text = (e.ProgressPercentage.ToString() + "%");
}

Go ahead, and you will see: it is fairly simple.

Fabian Bigler
  • 10,403
  • 6
  • 47
  • 70
2

When using a background worker you should be doing all of the non-UI processing in the background worker; you should not be using it to update the UI while still doing processing in the UI thread.

By moving the work to the DoWork handler of the BGW you free up the UI thread to allow it to process UI events, including the updating of the progress bar.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • Side question. I moved most of it into a BGW, but I have to now upload the processed values to the grid (UI interaction). How can I pass a value to the GUI? GUI.Invoke? – Alexey May 17 '13 at 20:13
  • 1
    @Alexey As I've said a number of times, the BGW provides a number of events for interacting with the UI. That's *it's entire reason for existing* instead of using `Thread` directly. If whatever it is is the results of the operation then set the `Result` property and use it in the completed event (which runs in the UI thread) to update the UI. If it's a UI change that is part of periodic progress updates then use the progress reporting aspect of its functionality. Details and examples of all of this can be seen from the MSDN pages around BGW. – Servy May 17 '13 at 20:16
  • I'm embarrassed I asked that question. Just so fried up that that I was stuck looping my thoughts through progressReport. Completely forgot about the result :D – Alexey May 17 '13 at 20:17
-2
private void btnCreate_Click(object sender, EventArgs e)
  {
      Progressbar1.Minimum = 1;

      Progressbar1.Maximum = dt.Rows.Count;

      Progressbar1.Value = 1;

      Progressbar1.Step = 1;


     for (int i = 1; i <= dt.Rows.Count; i++)
     {
            bool result=InsertUserdetails(Username);

            if(result== true)
            {
                 Progressbar1.PerformStep();
             }
     }
  }
SaravanaKumar
  • 739
  • 1
  • 7
  • 17