dobragab
dobragab

Reputation: 69

C# - ProgressBar with Marquee style

I'd like to add a ProgressBar on a form with Marquee style, to show the user something is in progress. During the time consuming operation the form doesn't get updated, so the ProgressBar also "freezes".

I've checked several posts about BackgroundWorker, but in my case the operation doesn't report progress, that's why I need a Marquee bar.

Any help or code snippet is appreciated.

Note: I need to use .NET 4.0 (for XP support) so I can't use Task.Run :(

button1_Click(object sender, EventArgs e)
{
    progressBar1.Style = ProgressBarStyle.Marquee;
    progressBar1.MarqueeAnimationSpeed = 50;

    // INSERT TIME CONSUMING OPERATIONS HERE
    // THAT DON'T REPORT PROGRESS
    Thread.Sleep(10000);

    progressBar1.MarqueeAnimationSpeed = 0;
    progressBar1.Style = ProgressBarStyle.Blocks;
    progressBar1.Value = progressBar1.Minimum;

}

Upvotes: 3

Views: 24680

Answers (4)

Andrei Krasutski
Andrei Krasutski

Reputation: 5257

Preferred solution

private void button1_Click(object sender, EventArgs e)
{
    button1.Enabled = false;
    progressBar1.Style = ProgressBarStyle.Marquee;
    progressBar1.MarqueeAnimationSpeed = 50;

    Task.Factory.StartNew(() => {
           // INSERT TIME CONSUMING OPERATIONS HERE
           // THAT DON'T REPORT PROGRESS
           Thread.Sleep(10000);
        }, TaskCreationOptions.LongRunning).
            ContinueWith(t => {
                progressBar1.MarqueeAnimationSpeed = 0;
                progressBar1.Style = ProgressBarStyle.Blocks;
                progressBar1.Value = progressBar1.Minimum;

                button1.Enabled = true;
                MessageBox.Show("Done!");
            }, TaskScheduler.FromCurrentSynchronizationContext());
}

P.S. To handle the possible cancellation of the operation, the example instantiates a CancellationTokenSource object that generates a cancellation token.

Upvotes: 0

Idle_Mind
Idle_Mind

Reputation: 39132

I've checked several posts about BackgroundWorker, but in my case the operation doesn't report progress, that's why I need a Marquee bar.

You can use the BackgroundWorker, just don't use the "progress" portion of it. These two things are not mutually exclusive...

Example:

    private void button1_Click(object sender, EventArgs e)
    {
        button1.Enabled = false;
        progressBar1.Style = ProgressBarStyle.Marquee;
        progressBar1.MarqueeAnimationSpeed = 50;

        BackgroundWorker bw = new BackgroundWorker();
        bw.DoWork += bw_DoWork;
        bw.RunWorkerCompleted += bw_RunWorkerCompleted;
        bw.RunWorkerAsync();
    }

    void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        // INSERT TIME CONSUMING OPERATIONS HERE
        // THAT DON'T REPORT PROGRESS
        Thread.Sleep(10000);
    }

    void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        progressBar1.MarqueeAnimationSpeed = 0;
        progressBar1.Style = ProgressBarStyle.Blocks;
        progressBar1.Value = progressBar1.Minimum;

        button1.Enabled = true;
        MessageBox.Show("Done!");
    }

Upvotes: 9

dobragab
dobragab

Reputation: 69

Solved. However, I think this is the least elegant way to handle it.

button1_Click(object sender, EventArgs e)
{
    progressBar1.Style = ProgressBarStyle.Marquee;
    progressBar1.MarqueeAnimationSpeed = 50;


    Task task = Task.Factory.StartNew(() =>
    {
        // INSERT TIME CONSUMING OPERATIONS HERE
        // THAT DON'T REPORT PROGRESS
        Thread.Sleep(10000);
    });

    while (!task.IsCompleted)
    {
         Application.DoEvents();
         Thread.Sleep(1);
    }

    progressBar1.MarqueeAnimationSpeed = 0;
    progressBar1.Style = ProgressBarStyle.Blocks;
    progressBar1.Value = progressBar1.Minimum;

}

Upvotes: 0

You still need to run your time consuming work on a different thread ... you are running it on the UI thread which means the UI doesn't have chance to do any UI updates (hence the freezing you witness)!

You should consider using Task<> instead of BackgroundWorker.

See https://msdn.microsoft.com/en-us/library/hh195051%28v=vs.110%29.aspx for more info on Task<>.


If you can't use Task<> then you should revert to BackgroundWorker and use the WorkCompleted event to stop the marquee and move your program onto its next operation.

Upvotes: 0

Related Questions