如何创建循环百分比(处理)[c#]

时间:2016-12-21 10:39:26

标签: c# wpf visual-studio loops percentage

示例:做9999次(可能超过)的事情

for (int i = 1; i <= 9999; i++)
{
    // do something
    label1.content = 100*i/9999 + "%" ;
}

我希望在编译时显示label1上的循环百分比我无法做几毫秒的任何事情而且我的标签只显示100%。有人有任何想法先生?谢谢。

3 个答案:

答案 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 answerthis

中所述的多重规划

但是在与Task.Yield()中断并在@ mm8解决方案中创建一个新线程之间需要权衡:

  1. 使用Task.Yield()休息更好,以防工作可以分段完成,每个部分都必须更新UI。
  2. 当UI更新很少(相对于完成工作)时,创建新线程会更好
  3. 请注意。顺便说一句,在10000循环中,我认为最好显示每千次进展