这个让我难过。我有一个简单的实用程序,用于帮助企业安装软件。一个组件备份用户当前在其计算机上的AppData文件,并将其保存到桌面上的文件夹中:
private void backupButton_Click(object sender, EventArgs e)
{
backgroundBackup.RunWorkerAsync();
}
private void backgroundBackup_DoWork(object sender, DoWorkEventArgs e)
{
...
}
private static void CopyAll(DirectoryInfo source, DirectoryInfo target)
{
...
}
// I removed the message boxes from DoWork, and added a RunWorkerCompleted event,
// but neither the confirmation nor the error messgae box from RunWorkerCompleted are shown.
private void backgroundBackup_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
...
}
这有效,但不会产生预期的结果。我将此操作放在后台线程上,因为每个用户备份的文件总大小可能接近一两个gb。每次运行时,目标中的一些(但不是全部)文件和文件夹都会复制到目标,并且每次复制的文件夹都会有所不同。有时只复制少量文件和文件夹,有时几乎所有内容都被复制,但从不复制整个目标。如果此操作放在一个简单的控制台应用程序中,它每次都有效。有什么我需要了解的BackgroundWorker类导致它不能在DoWork方法中完成所有工作吗?
编辑:
我想我可能会使BackgroundWorker类的问题复杂化。我和同事谈过,他们提出了一种创建新线程的简单方法来处理可能冗长的过程:
private void backupButton_Click(object sender, EventArgs e)
{
Thread backupThread = new Thread(backupThreadJob);
backupThread.Start();
}
private void backupThreadJob()
{
try
{
//copy files and stuff
}
catch(Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
}
这为我完成了工作;我尝试使用BackgroundWorker失败了,但却从未弄清楚为什么只复制了一些文件。谢谢大家的帮助!
答案 0 :(得分:4)
这不是一个完整的答案。但我可以想象以下内容与问题有关:
请记住BackgroundWorker
在另一个非UI线程上执行您的DoWork
方法,因此在那里调用MessageBox.Show
不是一个好主意。如果你在UI("前景")线程上运行,你应该只做UI内容:
您必须小心不要操作DoWork事件处理程序中的任何用户界面对象。而是通过ProgressChanged和RunWorkerCompleted事件与用户界面进行通信。 - MSDN reference page for the
BackgroundWorker
class
我可以想象,如果您的方法中某处出现异常,并且您想在catch
块中显示一个消息框,则此调用会触发另一个异常,该异常无法处理。因此你的方法过早地中止了。
答案 1 :(得分:1)
这是一个示例,显示您可以从后台线程调用消息框。 MessageBox.Show是一个静态方法调用,可以从后台线程调用。您永远不应该尝试访问UI层上的任何内容(包括绑定的后备对象 - 请在此处考虑WPF)。
以下是将其用于消息框的示例。
我想复制10个文件,然后在后台启动复制过程。发生错误(文件存在等),并且您希望提示用户覆盖 - 您可以显示一个消息框,要求用户进行确认。
private void button1_Click(object sender, EventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();
bw.RunWorkerCompleted += BwOnRunWorkerCompleted;
bw.DoWork += BwOnDoWork;
bw.RunWorkerAsync();
}
private void BwOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
MessageBox.Show("This is a message from a background thread");
}
private void BwOnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs runWorkerCompletedEventArgs)
{
MessageBox.Show("Your done");
}