【问题标题】:Update Label while processing in Windows Forms在 Windows 窗体中处理时更新标签
【发布时间】:2010-10-08 21:42:27
【问题描述】:

在处理时更新 Windows 窗体应用程序上的标签的最佳方法是什么?

当用户单击按钮时,我有一个循环对用户系统上的文件进行一些处理。

foreach (System.IO.FileInfo f in dir.GetFiles("*.txt"))
{
   // Do processing
   // Show progress bar
   // Update Label on Form, "f.Name is done processing, now processing..."
}

什么是示例代码?

这到底叫什么?是线程还是委托?

【问题讨论】:

    标签: winforms label progress


    【解决方案1】:

    您的快速解决方法是:

    Label1.Text = f.Name + " is done processing, now processing...";
    Label1.Refresh();
    

    您确实想避免DoEvents,否则如果您的用户反复按下表单上的按钮,您将遇到问题。

    【讨论】:

      【解决方案2】:

      应该在另一个线程上执行此操作,然后从该线程更新您的 UI 线程。您正在通过在 UI 线程上执行这项工作来阻止进一步的处理。

      如果您不能将此代码移至 UI 线程,那么您可以随时调用 Application.DoEvents,但我强烈建议您先探索以下选项:

      【讨论】:

      • 我同意这一点 - 特别是对于 BackgroundWorker。我自己经常使用它。 BackgroundWorkers 让这样的多线程操作变得简单易行!
      【解决方案3】:

      您需要将数据从一个线程传输到另一个线程。这可以通过多种方式完成...

      首先,您的“背景”线程可以更新某种“CurrentStatus”字符串变量,它会随着它的进行而改变。然后,您可以在表单上放置一个计时器,然后获取 CurrentStatus 变量并使用它更新标签。

      其次,您可以使用标签控件的 InvokeRequired 属性通过委托简单地将操作从后台线程调用到 UI 线程。比如……

      private delegate void UpdateStatusDelegate(string status);
      private void UpdateStatus(string status)
      {
          if (this.label1.InvokeRequired)
          {
              this.Invoke(new UpdateStatusDelegate(this.UpdateStatus), new object[] { status });
              return;
          }
      
          this.label1.Text = status;
      }
      

      您可以从任何线程(UI 或后台)调用该 UpdateStatus() 方法,它会检测是否需要在主 UI 线程上调用该操作(如果需要,是否需要)。

      要实际设置线程,您可以这样做:

          private void StartProcessing()
          {
              System.Threading.Thread procThread = new System.Threading.Thread(this.Process);
      
              procThread.Start();
          }
      
          private void Process() // This is the actual method of the thread
          {
              foreach (System.IO.FileInfo f in dir.GetFiles("*.txt"))
              {
                  // Do processing
                  // Show progress bar
                  // Update Label on Form, "f.Name is done processing, now processing..."
                  UpdateStatus("Processing " + f.Name + "...");                
              }
          }
      

      然后,当用户单击“GO”按钮时,您只需调用 StartProcessing()。

      【讨论】:

      • 这一定是完美的答案。
      【解决方案4】:

      如果您的处理时间很长,请在后台工作线程中进行。

      http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

      【讨论】:

        【解决方案5】:

        我也推荐使用:

        Application.DoEvents();
        

        处理当前在消息队列中的所有 Windows 消息。

        【讨论】:

        • 你读过帕特里克的回答吗:stackoverflow.com/a/570569/4731718 ?
        • 我真的很喜欢 DoEvents 的解决方案,但你是对的,我可能回答得太快了。至少它为其他人提供了如何使用 DoEvents 的想法
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-12
        • 2012-01-04
        • 1970-01-01
        相关资源
        最近更新 更多