1

I am wondering about the correct architecture to work with a progress bar in C#. But maybe it applies not only to C#, because I need an architectural look at this.

I'll explain my question with an example. The user presses a button and then the program starts to work on a huge algorithm. One part of the algorithm is taking very long. This part is on a very low level, far a way from the UI project and UI classes. I would like to show a progress bar to the user, so they can see the progress of this algorithm.

What is the better way? Is it ok to connect (reference) the view of the progress bar from the lower level project where the algorithm is? Or is it better to create the view of the progress bar in the existing UI project and send information about the state of the algorithm through all levels (from algorithm to UI)? Or is there some other, better way?

I think the second way is better, but it will be harder to implement.

8

A long running algorithm certainly could use some method of indicating it's progress. But it would be inappropriate for the algorithm to know that it's talking to a progress bar.

The algorithm should be able to talk to adapters that can take what the algorithm says about it's progress and turn it into a progress bar, a log file, or noise over an audio speaker.

Done this way, changes to any of those mediums won't impact the algorithm. Only the adapter for what changed.

And if it's really that important to you, yes I've been called a software architect. I prefer the term code monkey.

  • 1
    Observer Pattern, most likely. – Robert Harvey Jun 2 at 17:47
  • @RobertHarvey any event pattern that can cross to the GUI thread will work. I'd recommend observer if there was also a need to be able to dynamically register (or unregister) observers. – candied_orange Jun 2 at 18:22
  • @RobertHarvey: wasn't it you who wrote "Patterns are no building blocks"? ;-) – Doc Brown Jun 3 at 12:45
  • @DocBrown: Software patterns are advisory, not compulsory. You can still use them to inform your opinions, just don't expect to stitch together an application using them solely. – Robert Harvey Jun 3 at 14:52
  • @DocBrown: And no, I didn't write that. That was MichaelT. – Robert Harvey Jun 3 at 14:53
1

This is how I have approached this problem. There are a few points I find important.

  1. Possibility to subdivide the progress into parts. It seem fairly common to either have separate phases in the work, or that each work item takes a considerable amount of time, so each work item should also report progress.
  2. I do not want to worry about the update frequency of the GUI when writing the code for the algorithm. So reporting progress should ideally be just incrementing an integer. The GUI class should create a timer to poll the progress every second or so.

Therefore I end up with something like this

public interface IProgress {
    double Completed { get; } // From 0 to 1
}
public class MyProgress : IProgress{
    private IProgress[] subprogresses;
    public double Completed
        =>// Sums all the subprogresses, divided by the count.

    public MyProgress[] Split(int count) {
        // creates new MyProgress objects, sets them as subprogresses, and returns the created objects
    }

    public MyCountingProgress Counting(int totalCount) {
        // Creates a counting progress and sets it as the only subprogress
    };
}

public class MyCountingProgress : IProgress
{
    public MyCountingProgress(int totalCount)
    {
        TotalCount = totalCount;
    }

    public int Count;
    public int TotalCount { get; }
    public double Completed => this.Count / (double)this.TotalCount;
}

Calling would typically look something like this

var progress = new MyProgress();
Task longRunningTask = DoWork(progress);
MyProgressDialog.ShowDialog("please wait", longRunningTask, progress);

The progress dialog starts a timer to update the progress bar, registers a continuation on the task to close the dialog once it is completed (use TaskScheduler.FromCurrentSynchronizationContext() to ensure this runs on the gui thread), and shows a modal dialog.

Some further points:

  • You might want to include a description text for the current phase or work item.
  • you might want to include a cancellationToken in the progress, or keep it separate.
  • you can create a linq decorator that reports progress for each item in a list that is iterated.
  • you might want to include a weight for subprogresses, in case you know part of the work takes longer time than others.
  • you might want a separate property to indicate that a progress object is completed. The reason is that summation of floats might not sum to exactly 1.0.
0

First create a class that will contain e thread/task to do your background work. Add a method that will create and start the thread.

Add an event Progress with event arguments that have a progress indicator, like a number somewhere in between 0 and 1 or two numbers, current and total.

Have your thread execution method raise the event in each iteration, thus reporting progress.

Subscribe to the event in your UI component. Marshall to the UI thread in your handler method (use Invoke for Windows Forms).

The code executed on the UI thread can update your progress bar.

0

If you want the front-end to determine progress, you can use Microsoft API for reporting progress. Example For server-side progress you have to implement callbacks from server to client in your service layer. I am assuming your algorithm does not require server-side progress indication.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.