user3222101
user3222101

Reputation: 1330

How to use progressbar, backgroundworker, windows form together in C#?

I am stuck on an issue where I am using Backgroundworker to show the progress of my work in a progress bar. Code used for backgroundworker:-

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        Thread.Sleep(200);
        for (int i = 0; i <= 100; i++)
        {
           Delegate del= new DELEGATE(simulateHeavyWork);
           this.Invoke(del);

            backgroundWorker1.ReportProgress(i);
            if (backgroundWorker1.CancellationPending)
            {
                e.Cancel = true;
                backgroundWorker1.ReportProgress(0);
                return;
            }
        }

    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
        percentLabel.Text = e.ProgressPercentage.ToString() + "%";

    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Cancelled)
        {
            MessageBox.Show("Cancelled");
        }
        else
        {
            MessageBox.Show("Completed");
        }
    }

I have created a delegate on the code:-

public partial class Form1 : Form
{
    private delegate void DELEGATE();


    public Form1()
    {
        InitializeComponent();

    }
     private void simulateHeavyWork()
    {
        Thread.Sleep(100);

         ...lines of code to perform some search logs operation..
....
      }
 }

The functionality I want to achieve is that progress bar should report the progress of my function simulateHeavyWork() which is actually using UI thread as it needs to take input from my form controls and update it as well.

Now the problem which is happening is that code is actually calling simulateHeavyWork() and gives the output that is updating ui controls and work is done. (Note: I have used delegate here to avoid error cross controls running on ui thread as my function needs to use UI controls.)

Once that is done, it starts updating progress bar and which is wrong and looks like it calls simulateHeavyWork again and again with the gap of sleep(100).

Upvotes: 0

Views: 823

Answers (2)

Deniz
Deniz

Reputation: 888

user3222101, as Andy stated before, you are running simulateHeavyWork() continuously. Moreover, by calling Invoke you are running this method in the UI thread which cause an extra sleep in the UI thread. Basically Invoke uses the message loop (pump) of the Control you use it on (Form1 in that case) and put your delegate to the queue of the UI thread in order to execute. This is not a good practice I think, due to the Sleep() call and time consuming log operations in your simulateHeavyWork() method.

I hope, understand you problem clearly.What I suggest is separation of the time consuming log operations from UI thread. Do not spend the valuable time of UI thread with slow and boring I/O operations. Get the values from the controls (using Invoke in the BackgroundWorker as I will explain below), do whatever you want in BackgroundWorker and update your GUI (again using Invoke) without touching the UI thread for this kind of heavy tasks.

As Andy suggested, you can pass data via the parameter of RunWorkerAsync and you should create a class which can store any data you need (because it accepts only one parameter). However, you can get the values from your Form whenever you need from another thread by using Invoke. Invoke method also returns the value from your delegate (please see the example at the link below) and this gives you a chance to get the values of your controls on the form. Create a delegate which returns an object of type class that you crated for RunWorkerAsync and use this values in the BackgroundWorker thread. Please, have a look at the example in here.

public static string GetTextThreadSafe(this TextBox box)
{
    return GetTextBoxText(box);
}

Also, example uses Func<...> in order to return value.

By this way you can sleep (in BackgroundWorker thread) for a while then get the values from your controls (current values) and do whatever you want (again in BackgroundWorker thread). I think, this improves your code.

Upvotes: 1

Andrey Korneyev
Andrey Korneyev

Reputation: 26856

From your question: "which is wrong and looks like it calls simulateHeavyWork again and again with the gap of sleep(100)."

Of course it calls. Just look at your code:

for (int i = 0; i <= 100; i++)
{
   Delegate del= new DELEGATE(simulateHeavyWork);
    this.Invoke(del);

So you are calling simulateHeavyWork 100 times here. And since you've typed Thread.Sleep(100); in the body of simulateHeavyWork - gap between calls is about Sleep(100)

Upvotes: 0

Related Questions