0

I have a for loop (running in its own thread) in which I'm calculating the loop's progress and I want to display the progress value every time it changes, but I want to run the message display command outside the loop, so it doesn't pause the loop.

I have read How do I display progress during a busy loop?, but I don't want to use a background worker because I already have one that uses the instance of the class that starts the loop (i.e. I do not want to nest background workers). I am assuming that the alternative would be raising and listening to events, but I am not sure how to implement that in this case.

So, how can I solve this problem without the use of a background worker?

Community
  • 1
  • 1
IneedHelp
  • 1,630
  • 1
  • 27
  • 58

3 Answers3

1

If it's Winforms, you can just do a MyForm.BeginInvoke() with an anonymous delegate that updates the display of the progress. BeginInvoke is asynchronous so it won't block the current thread.

PhonicUK
  • 13,486
  • 4
  • 43
  • 62
0

You need to notify something like a LoopWatcher out of the loop thread.

public class ProgressEventArgs : EventArgs
{
    public int Number { get; private set; }
    public ProgressEventArgs(int num)
    {
        this.Number = num;
    }
}

public class Worker
{
    public event EventHandler<ProgressEventArgs> ProgressChanged = delegate { };

    public void DoSomething()
    {
        for (int i = 0; i < 10; i++)
        {
            ProgressChanged(this, new ProgressEventArgs(i));
            Thread.Sleep(1000);   //just an example here
        }
    }
}

You can see in Worker.DoSomething, there is a loop which costs time. I add an event in Worker, so outside the class, the subscriber can know the progress is changed.

var worker = new Worker();
worker.ProgressChanged += (s, e) => Console.WriteLine(e.Number);
Thread t = new Thread(worker.DoSomething);
t.Start();
Cheng Chen
  • 42,509
  • 16
  • 113
  • 174
0

Since the provided answers didn't meet my requirements, I did some research on events and solved the issue the way I initially wanted.

I declared an event in the class that is starting the loop:

public delegate void ProgressChangedEvHandler(int progress);

public event ProgressChangedEvHandler ProgressChanged;

private void OnProgressChanged(int progress)
{
    var handler = ProgressChanged;
    if (handler != null) handler(progress);
}

Then I invoked the event from within the loop:

for (var index = 0; index < arrayListCount; index++)
{
    var progress = (int) (100*(double) index/(double) arrayListCount);
    OnProgressChanged(progress);
}

and then I just created the listener (LoopClassInstance.ProgressChanged += LoopClassInstance_ProgressChanged;) in a different class (on a different thread):

private void LoopClassInstance_ProgressChanged(int progress)
{
    toolStripProgressBar1.Value = progress;
}
IneedHelp
  • 1,630
  • 1
  • 27
  • 58