使用 backgroundworker windows 表单时出现 CrossThreadMessagingException

CrossThreadMessagingException while using backgroundworker windows forms

我有一个 windows 表单应用程序和一个调用函数的按钮

我正在将大文件从一个地方复制到另一个地方。

花了很长时间,所以我决定使用进度条。 我需要从按钮点击调用后台进程

copyItems() 函数遍历列表项并从另一个地方复制项。它依次调用一个函数 CopyListItem 来复制一项。

我在 UI 中设置了一个文本框值,但它 returns 和

An exception 'Microsoft.VisualStudio.Debugger.Runtime.CrossThreadMessagingException' occurred`

如何在 backgroundworker todo 事件中调用 copy 函数
当我在点击事件中调用 runworkerasync 方法时,出现错误

    private void btnCopyItems_Click(object sender, EventArgs e)
    {
        backgroundWorker1.RunWorkerAsync();
    }

我创建了一个class

public partial class WorkerItem
{
    Helper Helper = new Helper();
    Complaints comp = new Complaints();
    public void CopyItem(SPListItem sourceItem, string destinationListName, string destServerURL)
    {
        //Copy sourceItem to destinationList
        try
        {
           // copies file from one location to another
        }
        catch (Exception ex)
        {
            Helper.LogtoList("Copy List ", string.Format("  {0} Message {1} Source {2} Stack trace {3}", ex.InnerException.ToString(), "Message " + ex.Message + "Source" + ex.Source + "Stack trace" + ex.StackTrace));
        }
    }
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar1.Value = e.ProgressPercentage;
    this.Text=e.ProgressPercentage.ToString();
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    try
    {
        WorkerItem workerItem = (WorkerItem)e.Argument;

        // check if the site valid
        Helper.siteName = txtSite.Text;
        {                          
            progressBar1.Maximum = itemscoll.Count;
            foreach (SPListItem sourceItem in itemscoll)
            {
                date = sourceItem["Date_x0020_Created"].ToString();
                if (!string.IsNullOrEmpty(date))
                {                               
                    workerItem.CopyItem(sourceItem, Helper.destinationListName, Helper.destServerURL);
                }
            }
        }

        Cursor.Current = Cursors.Default;
        MessageBox.Show(string.Format("Items Copied {0}", Helper.ItemsCopied.ToString()));
    }
    catch (Exception ex)
    {
        Helper.LogtoList("Main Function ", string.Format("{0} Message {1} Source {2} Stack trace {3}", ex.InnerException.ToString(), "Message " + ex.Message + "Source" + ex.Source + "Stack trace" + ex.StackTrace));
    }
}

使用以下方法之一来避免此异常。

this.Invoke((MethodInvoker)delegate
{
                    //code here you required
});

//------------或下面的代码------------

this.BeginInvoke((MethodInvoker)delegate
{
                      //code here you required
 });

您收到异常的原因是因为您在 BackgroundWorker 的 DoWork 事件中设置了 progressBar1.Maximum = itemscoll.Count;
没有 UI 更改 应该发生在您的 DoWork 事件中,这就是 ProgressChanged 事件的目的。

您的代码中也没有任何迹象表明您正在向主线程报告任何进度。

您处理示例的方式如下:

private void btnCopyItems_Click(object sender, EventArgs e)
{
  // Set the progressBar1.Maximum here before we call the background worker
  // This is what caused your exception, since it is an UI element that you are trying to change
  // inside your BackgroundWorker thread
  progressBar1.Maximum = 100;             // % based (Could be set onces and always left at 100)
  progressBar1.Maximum = itemscoll.Count; // x/y based
  // Either we use a percentage based progressbar or an x/y progressbar.
  // !!!! Choose one and use the appropriate values for it !!!!

  backgroundWorker1.RunWorkerAsync();
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
  try
  {
    WorkerItem workerItem = (WorkerItem)e.Argument;

    Helper.siteName = txtSite.Text;
    {
      // Variable for our progress calculation
      double curProgress; // % based

      // Since we need to report progress, let us use a for-loop instead of a foreach-loop
      for (int i = 0; i < itemscoll.Count-1; i++)
      {
        SPListItem sourceItem = itemscoll[i];
        date = sourceItem["Date_x0020_Created"].ToString();
        if (!string.IsNullOrEmpty(date))
        {
          workerItem.CopyItem(sourceItem, Helper.destinationListName, Helper.destServerURL);
        }

        // Calculate the current progress and call the ReportProgress event of our BackgroundWorker
        curProgress = ((double)i / (double)itemscoll.Count) * 100;                // % based
        ((BackgroundWorker)sender).ReportProgress(Convert.ToInt32(curProgress));  // % based

        // If we only go x/y progress based, then just send back our current state
        ((BackgroundWorker)sender).ReportProgress(0, i);  // x/y based
      }
    }

    Cursor.Current = Cursors.Default;
    MessageBox.Show(string.Format("Items Copied {0}", Helper.ItemsCopied.ToString()));
  }
  catch (Exception ex)
  {
    Helper.LogtoList("Main Function ", string.Format("{0} Message {1} Source {2} Stack trace {3}", ex.InnerException.ToString(), "Message " + ex.Message + "Source" + ex.Source + "Stack trace" + ex.StackTrace));
  }
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
  // % based
  progressBar1.Value = e.ProgressPercentage;
  this.Text = e.ProgressPercentage.ToString();

  // x/y based
  progressBar1.Value = Convert.ToInt32(e.UserState);
  this.Text = Convert.ToInt32(e.UserState).ToString();
}

注意两种不同的进度报告方式!
一种使用基于百分比的报告,另一种使用基于 x/y 的报告。
你想使用哪一个取决于你,但你需要选择一个并使用那个

有关 BackgroundWorker 的更多信息,请访问:
MSDN: BackgroundWorker Class
MSDN: How to: Run an Operation in the Background

最后一点:
您正在 BackgroundWorker 中使用 MessageBox.Show,不建议这样做,您应该停止工作线程并 return 向主线程显示适当的错误。