【问题标题】:C# update and append textbox value using backgroundworker processC# 使用后台工作进程更新和附加文本框值
【发布时间】:2010-07-21 19:15:36
【问题描述】:

我有一个 c# windows 窗体应用程序,我把它放在一起。很简单:\

输入:

  • 文本字符串
  • 源文件夹路径
  • 目标文件夹路径
  • 整数计数

应用程序在源文件夹中的文本文件中搜索输入的文本字符串;如果找到该字符串,则将该文件和具有相同名称的图像文件复制到目标文件夹。然而,它会根据整数输入多次执行此操作。

所以我有一个按钮,并在按钮单击事件中调用

ProcessImages(tbDID.Text, tbSource.Text, tbDest.Text, comboBoxNumberImages.SelectedItem.ToString());

这是:

private void ProcessImages(string DID, string SourceFolder, string DestFolder, string strNumImages)
        {         
            int ImageCounter = 0;
            int MaxImages = Convert.ToInt32(strNumImages);

            DirectoryInfo di = new DirectoryInfo(SourceFolder);

            foreach (FileInfo fi in di.GetFiles("*.txt"))
            {
                if (fi.OpenText().ReadToEnd().Contains(DID))
                {
                    //found one!
                    FileInfo fi2 = new FileInfo(fi.FullName.Replace(".txt", ".tif"));
                    if (fi2.Exists)
                    {
                        try
                        {
                            tbOutput.Text += "Copying " + fi2.FullName + " to " + tbDest.Text + "\r\n";
                            fi2.CopyTo(tbDest.Text + @"\" + fi2.Name, true);
                            tbOutput.Text += "Copying " + fi.FullName + " to " + tbDest.Text + "\r\n";
                            fi.CopyTo(tbDest.Text + @"\" + fi.Name, true);

                            ImageCounter++;
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.Message);
                        }
                    }
                }

                if (ImageCounter >= MaxImages)
                    break;

            }

        }

发生的情况是该过程运行良好,但我想在复制文件时更新表单上的文本框并显示进度。基本上,表单在运行时会出现空白,完成后输出在文本框中。我想实现一个 BackgroundWorker 让它在运行时更新 UI。

我浏览了这些示例,但并没有真正关注它们。我没有完成百分比值,我只想更新 .Text 每次迭代都会更改并显示。我什至认为我不一定需要将实际的复制操作放在不同的线程中,只是听起来需要与主 UI 线程分开运行。也许我把这完全复杂化了……有人能把我推向正确的方向吗?谢谢!

【问题讨论】:

    标签: c# backgroundworker


    【解决方案1】:

    您与后台工作人员的合作是正确的。这是我整理的一个示例,向您展示如何执行此操作。使用 Form1 创建一个新的 Windows 应用程序。向其中添加 4 个控件:label1、backgroundWorker1、button1 和 button2。然后使用此代码隐藏。然后,您可以使用 ReportProgress userState 向主线程报告您想要的任何内容。在这个例子中,我传递了一个字符串。 ProgressChanged 事件处理程序随后位于 UI 线程上,并更新文本框。

        public partial class Form1 : Form
    {
        int backgroundInt;
        public Form1()
        {
            InitializeComponent();
            backgroundWorker1.WorkerReportsProgress = true;
        }
    
        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            label1.Text = e.UserState as string;
        }
    
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            backgroundInt = 1;
            while (backgroundWorker1.CancellationPending == false)
            {
                System.Threading.Thread.Sleep(500);
                backgroundWorker1.ReportProgress(0, 
                    String.Format("I found file # {0}!", backgroundInt));
                backgroundInt++;
            }
        }
    
    
        private void button1_Click(object sender, EventArgs e)
        {
            backgroundWorker1.RunWorkerAsync();
        }
    
        private void button2_Click(object sender, EventArgs e)
        {
            backgroundWorker1.CancelAsync();
        }
    }
    

    【讨论】:

    • 就 OP 最初的“我没有百分比”投诉而言,重要的一点是 ReportProgress 不仅可以占百分比,而且也可以是一般的-目的对象 - 可以(如本例中)是一个字符串。
    • +1 表示 e.UserState 作为字符串。这对我来说远非显而易见。
    【解决方案2】:

    如果您使用后台工作程序,则可以使用 ReportProgress 方法返回任何整数,例如处理的记录数。它不一定是百分比。然后,在 ProgressChanged 处理程序中,您可以更新您的文本框。例如

    int count = e.ProgressPercentage;
    textBox1.Text = string.Format("{0} images processed.", count);
    

    如果您不想使用后台工作者,您可以在循环中调用 Application.DoEvents()。这将使 UI 有机会刷新自身并响应用户操作。但请注意 - 它会大大降低您的程序速度,因此您可能只想在每 100 次迭代时调用它。

    【讨论】:

      【解决方案3】:

      UI 不会更新,因为您不允许在长时间运行的文件处理循环中处理任何窗口消息。 WinForms 应用程序重绘以响应在主线程的消息队列中处理的 WM_PAINT 消息。

      最简单的解决方案是强制更新 UI:在修改循环内的文本框后尝试在表单上调用 Update()。

      您的应用仍将冻结 UI(对鼠标点击等无响应),但这至少应该会在屏幕上显示进度消息。如果你真的只需要更新显示,那么就到此为止吧。

      下一级解决方案是允许您的应用程序在文件处理循环中处理待处理的窗口消息。在循环中调用 Application.DoEvents()(而不是 form.Update)。这将允许表单使用您的文本输出更新重新绘制自身,并消除您的 UI 冻结 - 应用程序可以响应鼠标和键盘活动。

      不过,这里要小心 - 用户可以在当前活动正在进行时单击启动当前活动的按钮 - 重入。您至少应该禁用启动长时间运行文件处理的菜单或按钮,以防止重新进入。

      第三级解决方案是使用后台线程进行文件处理。这引入了许多您需要注意的新问题,并且在许多情况下线程是多余的。如果您不允许用户在文件处理过程中对您的应用执行任何其他操作,那么将文件处理推到后台线程没有多大意义。

      【讨论】:

      • OP 已经走上了正轨,那就是使用 BackgroundWorker,它既创建了后台线程(嗯,它使用了一个池线程),又处理了你提到的一些问题你的最后一段。
      • 在文件处理过程中,OP 并不表示用户在 UI 中还有其他事情要做,因此后台线程可能会过度杀伤 IMO。
      【解决方案4】:

      只需创建一个 (1) 一个委托来包装您的 ProcessImages 方法调用,(2) 使用委托触发该调用,以及 (3) 当您希望从您的 ProcessImages 方法更新文本框时,检查交叉头操作并确保从主线程进行更新:

      delegate void ProcessImagesDelegate(string did, string sourceFolder, string destFolder, string strNumImages);
      
      private void ProcessImages(string DID, string SourceFolder, string DestFolder, string strNumImages)
      {
          // do work
      
          // update textbox in form
          if (this.textBox1.InvokeRequired)
          {
              this.textBox1.Invoke(new MethodInvoker(delegate() { this.textBox1.Text = "delegate update"; }));
          }
          else
          {
              this.textBox1.Text = "regular update";
          }
      
          // do some more work
      }
      
      public void MyMethod()
      {
          new ProcessImagesDelegate(ProcessImages).BeginInvoke(tbDID.Text, tbSource.Text, tbDest.Text, comboBoxNumberImages.SelectedItem.ToString(), null, null);
      }
      

      【讨论】:

      • 为什么这比使用 BackgroundWorker 更好?
      • 由于他们都使用线程池,并且没有一个比另一个给我更好的性能,我更喜欢委托,因为他们通常给我更干净/更简单的代码(恕我直言),而且这只是另一种方式完成他想要的事情
      【解决方案5】:

      我不必创建后台工作者。我所做的只是调用.Update(),然后是System.Threading.Thread.Sleep(100),它开始工作了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多