我在一个表单下面使用了一个后台工作者,当我点击一个按钮它应该生成一个文档,但是GUI挂起,我不知道为什么会这样做,因为我觉得我正在使用backgroundworker。任何人都可以帮忙吗?
private void btn_GenerateRevDoc_Click(object sender, EventArgs e)
{
DOC_GenerateVersDocBackgroundWorker = new BackgroundWorker();
DOC_GenerateVersDocBackgroundWorker.WorkerReportsProgress = true;
DOC_GenerateVersDocBackgroundWorker.WorkerSupportsCancellation = true;
DOC_GenerateVersDocBackgroundWorker.DoWork += new DoWorkEventHandler(DOC_GenerateVersDocBackgroundWorker_DoWork);
DOC_GenerateVersDocBackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(DOC_GenerateVersDocBackgroundWorker_ProgressChanged);
DOC_GenerateVersDocBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(DOC_GenerateVersDocBackgroundWorker_RunWorkerCompleted);
System.Threading.Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
if (Db.docVersionHistory != null && Db.docVersionHistory.Count > 0)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Title = "Export Review To";
sfd.Filter = "Word files (*.doc)|*.doc|All files (*.*)|*.*";
sfd.FilterIndex = 1;
sfd.FileName = "";
if (sfd.ShowDialog() == DialogResult.OK)
{
if (!DOC_GenerateVersDocBackgroundWorker.IsBusy)
DOC_GenerateVersDocBackgroundWorker.RunWorkerAsync(sfd.FileName);
}
}
else
{
MessageBox.Show("No Review Records were found!");
}
}
void DOC_GenerateVersDocBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
if (this.InvokeRequired)
{
Invoke(new MethodInvoker(delegate
{
DocumentsNavigator.GenerateWordRevisionHistoryDoc(DOC_GenerateVersDocBackgroundWorker, versionsList, Db, (string)(e.Argument));
}));
}
else
{
DocumentsNavigator.GenerateWordRevisionHistoryDoc(DOC_GenerateVersDocBackgroundWorker, versionsList, Db, (string)(e.Argument));
}
}
答案 0 :(得分:1)
您并不完全了解BackgroundWorker
应该如何使用,以及Invoke
方法的用途。
Invoke
方法导致在UI线程上调用代码。因此,请勿通过DocumentsNavigator.GenerateWordRevisionHistoryDoc
传递Invoke
方法。 RunWorkerAsync
没问题。我不知道versionsList
和Db
是什么类型,但如果它们是UI对象,则可能需要将所需的值复制到新变量中。例如,如果versionsList
是ListBox
,则应将所选值复制到新的string[]
,并将string[]
用作方法的参数。
以下是您认为您想要做的事情:
创建新的后台工作程序
初始化您的后台工作人员
停用btn_GenerateRevDoc
按钮
显示SaveFileDialog
启动BackgroundWorker(RunWorkerAsync
)
在ProgressChanged
事件中,如果您正在显示进度条或
什么,你可以更新,这次你必须通过它
通过Invoke
方法。
在RunWorkerCompleted
事件中,显示消息框或其他内容,
并再次启用btn_GenerateRevDoc
按钮
哦,这行应该绝对删除:
System.Threading.Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
答案 1 :(得分:0)
在您的后台工作人员中,您再次将所有工作转发到UI线程,这就是您的UI挂起的原因
if (this.InvokeRequired)
{
//this executes the work on UI thread
Invoke(new MethodInvoker(delegate
{
DocumentsNavigator.GenerateWordRevisionHistoryDoc(DOC_GenerateVersDocBackgroundWorker, versionsList, Db, (string)(e.Argument));
}));
}
else
{
//it will also be executed on UI thread
DocumentsNavigator.GenerateWordRevisionHistoryDoc(DOC_GenerateVersDocBackgroundWorker, versionsList, Db, (string)(e.Argument));
}
}
答案 2 :(得分:0)
从您的代码当我点击一个按钮时,它应该生成一个文档,但GUI挂起
我可以看到您应该输入文件名并单击确定。是否在某处打开了保存对话框?
尝试在不使用后台工作程序的情况下编写相同的代码。它还挂着吗?此外,观察到条件if (!DOC_GenerateVersDocBackgroundWorker.IsBusy)
没有意义,因为每次点击按钮都会创建一个新的背景工作者
答案 3 :(得分:0)
问题是您正在运行在工作线程中挂起GUI但在Invoke方法中执行此操作的代码。
Invoke方法在GUI的线程中运行代码,因此它会挂起。
如果你绝对必须在GUI线程中调用DocumentsNavigator.GenerateWordRevisionHistoryDoc
,我就不知道如何在不挂起GUI的情况下进行此调用。
尝试重新考虑您的代码,这样您就不必在Invoke方法中运行BackgroungWorker中的任何代码。
答案 4 :(得分:-1)
你做的事情不安全。
而不是Invoke尝试
if (this.InvokeRequired)
{ this.BeginInvoke(new MethodInvoker(delegate
{