Reputation: 69
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
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
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
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
Reputation: 3290
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