使用backgroundworker窗体时使用CrossThreadMessagingException

时间:2015-03-10 12:33:43

标签: c# .net winforms c#-4.0 c#-3.0

我有一个Windows窗体应用程序,并有一个调用函数的按钮

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

这需要很长时间,所以我决定使用进度条。 我需要从按钮单击

调用后台进程

copyItems()函数遍历列表项并从其他位置复制项。它又调用一个复制一个项目的函数CopyListItem

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

  

发生了'Microsoft.VisualStudio.Debugger.Runtime.CrossThreadMessagingException'异常`

如何在backgroundworker todo事件中调用复制功能
当我在click事件中调用runworkerasync方法时出现错误

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

我创建了一个类

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));
    }
}

2 个答案:

答案 0 :(得分:1)

您获得异常的原因是因为您在BackgroundWorker的progressBar1.Maximum = itemscoll.Count;事件中设置了DoWork
在您的DoWork事件中应该发生无UI更改,这就是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,建议不要这样做,您应该停止工作线程并向主线程返回相应的错误以显示。

答案 1 :(得分:0)

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

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

// ----------或以下代码----------

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