我有一个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));
}
}
答案 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
});