C#-带有字幕风格的ProgressBar
我想在带有字幕样式的表单上添加一个ProgressBar,向用户显示正在进行的操作。在耗时的操作过程中,表单不会得到更新,因此ProgressBar也会“冻结” 我已经检查了好几篇关于BackgroundWorker的帖子,但在我的案例中,操作没有报告进度,这就是为什么我需要一个选框栏 欢迎提供任何帮助或代码片段 注意:我需要使用.NET 4.0(用于XP支持),因此无法使用任务。运行:(C#-带有字幕风格的ProgressBar,c#,progress-bar,C#,Progress Bar,我想在带有字幕样式的表单上添加一个ProgressBar,向用户显示正在进行的操作。在耗时的操作过程中,表单不会得到更新,因此ProgressBar也会“冻结” 我已经检查了好几篇关于BackgroundWorker的帖子,但在我的案例中,操作没有报告进度,这就是为什么我需要一个选框栏 欢迎提供任何帮助或代码片段 注意:我需要使用.NET 4.0(用于XP支持),因此无法使用任务。运行:( 您仍然需要在另一个线程上运行耗时的工作…您正在UI线程上运行它,这意味着UI没有机会进行任何UI更新(因此
您仍然需要在另一个线程上运行耗时的工作…您正在UI线程上运行它,这意味着UI没有机会进行任何UI更新(因此您看到的冻结)
您应该考虑使用<代码>任务<代码>代替<代码>后台工作人员< /> >
有关任务的更多信息,请参见如果无法使用
任务
,则应返回到BackgroundWorker
,并使用工作完成
事件停止字幕并将程序移动到下一个操作。已解决。但是,我认为这是最不优雅的处理方式
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;
}
我已经查看了好几篇关于BackgroundWorker的帖子,但就我而言
操作不报告进度,这就是为什么我需要一个选框栏
你可以使用BackgroundWorker,只是不要使用它的“进度”部分。这两件事不是相互排斥的
例如:
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());
}
另外,为了处理可能的操作取消,该示例实例化了一个生成取消令牌的
CancellationTokenSource
对象。谢谢,我来看看。请注意,我不能使用Task.Run,正如我在编辑中提到的。有没有.NET 4.0支持的替代方法?您知道iter的计数吗在您的消费过程开始时要做什么?在这种情况下,我可能会向您建议一些实现。这不是一个迭代,更像是等待MySQL连接或LDAP响应。通常将您的单击处理程序保持在这样的轮询循环中是一个非常糟糕的主意。听起来不错!是否可以从bw_Ru访问所有表单控件nWorkerCompleted?(它是否在同一线程上运行?)按钮1.Enabled=true;MessageBox.Show(“Done!”);这表明是这样。是的,您可以从RunWorkerCompleted()安全地访问所有控件
事件,因为它已经由BackgroundWorker控件为您封送到主UI线程。如果您将来使用它,ProgressChanged()
事件也是如此。
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());
}