JohnH
JohnH

Reputation: 45

Updating progressbar through backgroundworker in method

My programm (in C# using Windows Forms) is reading and parsing large amounts of Data and I'm using a Backgroundworker which calls those global methods (reading and parsing). I'd like to keep the user updated on how long it's going to take, so the Backgroundworker is supposed to display what action its doing and has a progressbar that should fill for every individual action too.

Unfortunately, I can't get it to work, as the progressbar just doesn't update at all and just stays empty.

Here is what I have so far:

        private void InitializeBackgroundWorker()
    {
        backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
        backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
        backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
    }

    private void buttonParse_Click(object sender, EventArgs e)
    {
        DescriptionLabel.Visible = true;
        progressBar1.Visible = true;
        backgroundWorker1.RunWorkerAsync();
    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
    }
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {

        BackgroundWorker worker = sender as BackgroundWorker;
        Methods.ParsePerfusionData(backgroundWorker1); //Also tried using 'worker' here, but didnt work either
    }

And in the method it looks like that:

    public static void ParsePerfusionData(BackgroundWorker worker)
    {
            for (int i = 2; i < Globals.DataList.Count; i++)
        {

                worker.ReportProgress(i / amount * 100);
                rest of the code etc.
        }
    }

Can I not use a backgroundworker in a global method like that? Thanks in advance!

Upvotes: 1

Views: 82

Answers (2)

bommelding
bommelding

Reputation: 3037

When i < amount then i / amount * 100 = 0 * 100 = 0.

Simply use i * 100 / amount instead.

Also make sure backgroundWorker1.WorkerReportsProgress = true

Upvotes: 1

Christopher
Christopher

Reputation: 9814

You can only report progress between distinct operations. That means either:

  • using a very modern class that supports this level of reporting. Such a classs might not exist for your case.
  • reverse engineering parts of the code down to the loop you want to make reporting on. Usually the loop that itterates over files or the like.

GUI updates must be contained to RunWorkerCompelted and ProgressReport events. And depending on how often updates happen, ProgressReport may have to be kept to only updating a progress bar.

Here some old code I wrote with BackgroundWorker wich should get you started:

#region Primenumbers
private void btnPrimStart_Click(object sender, EventArgs e)
{
    if (!bgwPrim.IsBusy)
    {
        //Prepare ProgressBar and Textbox
        int temp = (int)nudPrim.Value;
        pgbPrim.Maximum = temp;
        tbPrim.Text = "";

        //Start processing
        bgwPrim.RunWorkerAsync(temp);
    }
}

private void btnPrimCancel_Click(object sender, EventArgs e)
{
    if (bgwPrim.IsBusy)
    {
        bgwPrim.CancelAsync();
    }
}

private void bgwPrim_DoWork(object sender, DoWorkEventArgs e)
{
    int highestToCheck = (int)e.Argument;
    //Get a reference to the BackgroundWorker running this code
    //for Progress Updates and Cancelation checking
    BackgroundWorker thisWorker = (BackgroundWorker)sender;

    //Create the list that stores the results and is returned by DoWork
    List<int> Primes = new List<int>();


    //Check all uneven numbers between 1 and whatever the user choose as upper limit
    for(int PrimeCandidate=1; PrimeCandidate < highestToCheck; PrimeCandidate+=2)
    {
        //Report progress
        thisWorker.ReportProgress(PrimeCandidate);
        bool isNoPrime = false;

        //Check if the Cancelation was requested during the last loop
        if (thisWorker.CancellationPending)
        {
            //Tell the Backgroundworker you are canceling and exit the for-loop
            e.Cancel = true;
            break;
        }

        //Determin if this is a Prime Number
        for (int j = 3; j < PrimeCandidate && !isNoPrime; j += 2)
        {
            if (PrimeCandidate % j == 0)
                isNoPrime = true;
        }

        if (!isNoPrime)
            Primes.Add(PrimeCandidate);
    }

    //Tell the progress bar you are finished
    thisWorker.ReportProgress(highestToCheck);

    //Save Return Value
    e.Result = Primes.ToArray();
}

private void bgwPrim_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    pgbPrim.Value = e.ProgressPercentage;
}

private void bgwPrim_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    pgbPrim.Value = pgbPrim.Maximum;
    this.Refresh();

    if (!e.Cancelled && e.Error == null)
    {
        //Show the Result
        int[] Primes = (int[])e.Result;

        StringBuilder sbOutput = new StringBuilder();

        foreach (int Prim in Primes)
        {
            sbOutput.Append(Prim.ToString() + Environment.NewLine);
        }

        tbPrim.Text = sbOutput.ToString();
    }
    else 
    {
        tbPrim.Text = "Operation canceled by user or Exception";
    }
}
#endregion

Upvotes: 0

Related Questions