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

How to create percentage of loop(processing) [c#]

示例:做某事 9999 次(可能更多)

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

并且我想在编译时显示 label1 上的循环百分比我无法在几毫秒内执行任何操作并且我的标签仅显示 100%。有人知道先生吗?谢谢。

那是因为您在循环内计算时阻塞了 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);
    }

但这是一种不好的做法!

您不能在同一线程上同时 运行 循环和更新 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 + "%"));
            }
        });

my message box immediately show message after i run command while percentage is running

如前所述,任务正在另一个线程上执行。因此它将 运行 与 UI 线程 并行 。这就是为什么 UI 可以在循环 运行ning 时更新的原因。

您可以使用 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());

@mm8 解决方案没问题,但是每次从新线程到 UI 线程的并发往返都会延迟你的循环。

如果您希望循环尽早结束而不会使 UI(以及您的目标 NET Framework 4.5 或更高版本)膨胀,您可以使用与旧的 DoEvents 等效的异步任务方法: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
        }
    }

这个解决方案很简单,并且是为什么异步不需要始终如 and

中所述的多线程的示例

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

  1. 使用 Task.Yield() 休息一下更好,以防工作可以分段完成,并且在每个分段中必须更新 UI。
  2. 当 UI 更新很少(相对于完成的工作)时,创建一个新线程更好

注意。顺便说一下,在 10000 循环中,我认为最好显示每千个进度