示例:做9999次(可能超过)的事情
for (int i = 1; i <= 9999; i++)
{
// do something
label1.content = 100*i/9999 + "%" ;
}
我希望在编译时显示label1上的循环百分比我无法做几毫秒的任何事情而且我的标签只显示100%。有人有任何想法先生?谢谢。
答案 0 :(得分:3)
您无法同时运行循环并在同一个线程上更新UI。这就是为什么你应该总是在后台线程上执行任何长时间运行的工作,并使用调度程序定期更新UI。
在后台线程上运行某些代码的最简单方法是使用任务并行库(TPL)来启动新任务:
Task.Run(()=>
{
for (int i = 1; i <= 9999; i++)
{
System.Threading.Thread.Sleep(1500); //simulate long-running operation by sleeping for 1.5s seconds...
label1.Dispatcher.BeginInvoke(new Action(() => label1.Content = 100 * i / 9999 + "%"));
}
});
我的消息框在运行百分比正在运行时立即显示消息
如前所述,Task正在另一个线程上执行。因此它将与UI线程在 parallel 中运行。这就是为什么在循环运行时可以更新UI的原因。
您可以使用Task.ContinueWith方法在任务完成后显示MessageBox:
int i = 1;
Task.Run(() =>
{
for (; i <= 9999; i++)
{
System.Threading.Thread.Sleep(1500); //simulate long-running operation by sleeping for 1.5s seconds...
label1.Dispatcher.BeginInvoke(new Action(() => label1.Content = (i / 9999) * 100 + "%"));
}
}).ContinueWith(t =>
{
MessageBox.Show("done..." + i.ToString());
}, System.Threading.CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
答案 1 :(得分:0)
那是因为你在循环中计算时阻止了UI线程。这些事情应该在回调方法的不同线程中进行。
作为解决方法,您可以导入system.windows.forms.dll
程序集并调用System.Windows.Forms.Application.DoEvents();
for (int i = 1; i <= 9999; i++)
{
System.Windows.Forms.Application.DoEvents();
// do something
label1.Content = 100 * i / 9999 + "%";
Thread.Sleep(10);
}
但这是一种不好的做法!
答案 2 :(得分:0)
@ mm8解决方案没问题,但是从新线程到UI线程的每次并发往返都会延迟你的循环。
如果您希望尽可能早地结束循环而不膨胀UI(以及您的目标.NET Framework 4.5或更高版本),则可以使用等效于旧DoEvents的异步Task方法:Task.Yield()。
private async void Button_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 10000; i++)
{
//Do something
//Simulate work with Task.Delay(millisecondos)
Label1.Content = (i * 100 / 10000) + "%";
await Task.Yield(); //give opportunity to dispatch other events
}
}
此解决方案很简单,并且是一个示例,说明为什么异步不需要始终如this answer和this
中所述的多重规划但是在与Task.Yield()中断并在@ mm8解决方案中创建一个新线程之间需要权衡:
请注意。顺便说一句,在10000循环中,我认为最好显示每千次进展