Whyrusleeping
Whyrusleeping

Reputation: 929

How to update progress bar from other class?

I have a command line tool written in c# (that i have the source of) that I am making a gui for in visual studio 2010. In the gui I want to update the progress bar to reflect the progress of the tools operations. How would I signal from inside the tool that progress has been made and to update the progress bar? Some simplified example code of what im doing.

private void doThings_Click(object sender, EventArgs e)
{
  myToolInstance.doWorkThatNeedsToReportProgress();
}

The work that is being done by the tool is a series of function calls, normally around 30. I want to update the progress bar each time one of those finishes.

Upvotes: 7

Views: 24220

Answers (2)

Olivier Jacot-Descombes
Olivier Jacot-Descombes

Reputation: 112362

Create a public property or a public method in the form containing the progress bar

public void SetProgress(int progress)
{
    progressBar.Progress = progress;
}

Now you can update the progress bar with

myForm.SetProgress(50);

Another approach is to have a ProgressChanged event somewhere and let the form subscribe to this event.

public class Tool {
    public event Action<int> ProgressChanged;

    private void OnProgressChanged(int progress) 
    {
        ProgressChanged?.Invoke(progress);
    }

    public void DoSomething()
    {
        ...
        OnProgressChanged(30);
        ...
    }
}

In the form you would have something like this

private Tool _tool;

public MyForm () // Constructor of your form
{
    _tool = new Tool();
    _tool.ProgressChanged += Tool_ProgressChanged;
}

private void Tool_ProgressChanged(int progress)
{
    progressBar.Progress = progress;
}

Upvotes: 17

Mike-Kilo
Mike-Kilo

Reputation: 1312

Golden shovel candidate, nevertheless I came across similar issue and I'd like to share my solution here.

In general, I have a method that will be run asynchronously due to computational complexity. One of the input parameters is the progress bar itself.
Since the ProgressBar is of nullable type, it is not mandatory when invoking the method.
Inside the method I do the progress bar advancing in its dispatcher - in many cases the method will be run on other thread that owns the progress bar. To handle the null possibility of the progress bar, I use the nullable operator:

private string MyMethod(int input, ProgressBar progressBar)
{
    while(!done)
    {
        // Do the hard work.

        progressBar?.Dispatcher.Invoke(() => progressBar.Value++);
    }
}

Now, I need to set the progress bar Maxiumim before I call the method and it must be set to the expected length.

Some may say that I'm causing great inefficiency calling the dispatcher each time I need to advance the progress bar. Yes, I agree to that, however it all depends on how many steps we need to go through. That's why I've run some quick benchmark.

For my case I had more than 300,000 (three hundred thousands) steps (each step was formatting some data to a string and writing that string to a file). Running the method without the progress bar update was my reference.

  • updating progress bar each step made the run time longer by more than 2,000% (twenty times longer)
  • updating progress bar every 10th step made the run time longer by more than 250% (two and a half times longer)
  • updating progress bar every 100th step made the run time longer by around 15% (longer by about 1/8th)
  • updating progress bar every 1000th step made the run time longer by around 3% (marginal difference)

With my progress bar being 240 pixels wide I've settled for progress bar maximum of about 300 and updating it accordingly receiving very smooth animation without noticeable performance penalty.

Upvotes: 0

Related Questions