C# - 带跑马灯样式的 ProgressBar
C# - ProgressBar with Marquee style
我想在具有跑马灯样式的窗体上添加 ProgressBar,以向用户显示正在进行的事情。在耗时的操作过程中,表单没有得到更新,因此 ProgressBar 也 "freezes".
我查看了几篇关于 BackgroundWorker 的帖子,但在我的例子中,操作没有报告进度,这就是为什么我需要一个 Marquee 栏。
感谢任何帮助或代码片段。
注意:我需要使用 .NET 4.0(用于 XP 支持)所以我不能使用 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;
}
您仍然需要 运行 在另一个线程上进行耗时的工作...您 运行 在 UI 线程上进行它,这意味着 UI没有机会做任何 UI 更新(因此你看到了冻结)!
您应该考虑使用 Task<>
而不是 BackgroundWorker
。
有关 Task<>
的更多信息,请参阅 https://msdn.microsoft.com/en-us/library/hh195051%28v=vs.110%29.aspx。
如果您不能使用 Task<>
那么您应该恢复到 BackgroundWorker
并使用 WorkCompleted
事件来停止选取框并将您的程序移至下一个操作。
已解决。但是,我认为这是最不优雅的处理方式。
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;
}
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.
您可以使用 BackgroundWorker,只是不要使用它的 "progress" 部分。这两件事并不相互排斥...
示例:
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!");
}
首选方案
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。为了处理可能的操作取消,示例实例化了一个生成取消标记的 CancellationTokenSource
对象。
我想在具有跑马灯样式的窗体上添加 ProgressBar,以向用户显示正在进行的事情。在耗时的操作过程中,表单没有得到更新,因此 ProgressBar 也 "freezes".
我查看了几篇关于 BackgroundWorker 的帖子,但在我的例子中,操作没有报告进度,这就是为什么我需要一个 Marquee 栏。
感谢任何帮助或代码片段。
注意:我需要使用 .NET 4.0(用于 XP 支持)所以我不能使用 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;
}
您仍然需要 运行 在另一个线程上进行耗时的工作...您 运行 在 UI 线程上进行它,这意味着 UI没有机会做任何 UI 更新(因此你看到了冻结)!
您应该考虑使用 Task<>
而不是 BackgroundWorker
。
有关 Task<>
的更多信息,请参阅 https://msdn.microsoft.com/en-us/library/hh195051%28v=vs.110%29.aspx。
如果您不能使用 Task<>
那么您应该恢复到 BackgroundWorker
并使用 WorkCompleted
事件来停止选取框并将您的程序移至下一个操作。
已解决。但是,我认为这是最不优雅的处理方式。
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;
}
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.
您可以使用 BackgroundWorker,只是不要使用它的 "progress" 部分。这两件事并不相互排斥...
示例:
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!");
}
首选方案
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。为了处理可能的操作取消,示例实例化了一个生成取消标记的 CancellationTokenSource
对象。