views:

94

answers:

4

How do I report change of the CountValue from this class to a backgroundworker

class SomeOtherClass
{
    public void CountUp()
    {
        int CountValue;
        for (int i = 0; i < 100000000; i++)
            CountValue = i;
    }
}

Here is the implemetation of the DoWork function

   private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;
        SomeOtherClass MyOtherClass = new SomeOtherClass();
        int CountValue;
        if ((worker.CancellationPending == true))
        {
            e.Cancel = true;
        }
        else
        {
            MyOtherClass.CountUp();
            worker.ReportProgress(CountValue);
        }
    }
A: 

Not sure I understand but I'll give it a shot. Why not change CountUp() to return a value?

public int CountUp()    
{
    int CountValue;
    for (int i = 0; i < 100000000; i++)
        CountValue = i;    

    return CountValue;
}

The purpose of this code doesn't make sense to me so I'm not sure I understand what you were trying to accomplish.

Cory Charlton
A: 

I don't think you understand how local variables work... the CountValue in your CountUp method will only write to the local variable in your CountUp method. It does not affect the CountUp variable in your backgroundWorker_DoWork method. You would have to move CountUp to the DoWork method for it to work.

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;
    for (int i = 0; i < 100000000; i++)
    {
        if (worker.CancellationPending)
        {
            e.Cancel = true;
            break;
        }

        worker.ReportProgress(i);
    }
}
nasufara
Well he could expose the value through a property of SomeClass but it wouldn't change the fact that the call to MyOtherClass.CountUp() will block.
Cory Charlton
the countUp method was just an example. The method I'm using is too big to put it into the DoWork method. So I need to understand what I have to do to access the CountValue from within the DoWork method
tomfox66
Perhaps do what Cory suggested, by exposing it through a property, like so: `public int Count { get { return _count; } }`, assuming you had an instance variable called `_count`.
nasufara
+1  A: 

In the way that SomeOtherClass looks now there is no obvious way. If you can change SomeOtherClass you could add an event:

class CountEventArgs : EventArgs
{
    public int CountValue { get; private set; }
    public CountEventArgs (int countValue)
    {
        CountValue = countValue;
    }
}
class SomeOtherClass
{
    public event EventHandler<CountEventArgs> CountValueChanged;
    public void CountUp()
    {
        int CountValue;
        for (int i = 0; i < 100000000; i++)
        {
            CountValue = i;
            OnCountValueChanged(new CountEventArgs(CountValue));
        }
    }
    private void OnCountValueChanged(CountEventArgs e)
    {
        EventHandler<CountEventArgs> temp = CountValueChanged;
        if (temp != null)
        {
            temp(this, e);
        }
    }
}

Then you can set up an event handler and use the ReportProgress method of the BackgroundWorker to relay the information to the UI:

BackgroundWorker worker = sender as BackgroundWorker;
SomeOtherClass MyOtherClass = new SomeOtherClass();
// set up an anonymous method as event handler for the CountValueChanged
// event. This event handler passes the count value on to the ReportProgress
// method of the background worker, which in turn will raise the ProgressChanged
// event on the UI thread.
MyOtherClass.CountValueChanged += (eventSender, eventArgs) =>
{
    worker.ReportProgress(eventArgs.CountValue);
};

MyOtherClass.CountUp();
Fredrik Mörk
+1  A: 

You have made a lot of errors in your code. In particular, you can't expect Windows to keep up when you are sending it a new event millions of times per second. Try only sending an update when you have completed a large block of work. Also, the parameter for ReportProgress should be a percentage (0 - 100). If you want to send data other than a percentage, use the user state parameter. Here is some code you can use:

using System;
using System.Windows.Forms;
using System.ComponentModel;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            backgroundWorker.RunWorkerAsync();
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            backgroundWorker.CancelAsync();
        }

        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = (BackgroundWorker)sender;

            int countValue = 0;
            int max = 100000000;
            for (int i = 0; i < max; i++)
            {
                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }

                countValue = i;
                if (i % 1000000 == 0)
                    worker.ReportProgress(i / (max / 100), i);
            }
            worker.ReportProgress(100, max);
        }

        private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar.Value = e.ProgressPercentage;
            labelCounter.Text = ((int)e.UserState).ToString();
        }
    }
}

Note: remember to set the worker's SupportsProgress and SupportsCancellation to true in the designer.

Mark Byers