不创建新的Backgroundworker实例-C#
我正在创建一个利用backgroundworker运行流程的进度表。它在第一次显示表单时运行正常,但是在那之后我得到了错误 其他信息:此操作已完成操作 打电话给它,再打电话是非法的 当我尝试调用不创建新的Backgroundworker实例-C#,c#,winforms,C#,Winforms,我正在创建一个利用backgroundworker运行流程的进度表。它在第一次显示表单时运行正常,但是在那之后我得到了错误 其他信息:此操作已完成操作 打电话给它,再打电话是非法的 当我尝试调用BackgroundWorker.ReportProgress()方法时 我很困惑,因为我在块中创建进度表单,如下所示: using (ProgressForm FPProgForm = new ProgressForm(TheUI)) { FPProgForm.ShowDialog();
BackgroundWorker.ReportProgress()方法时
我很困惑,因为我在块中创建进度表单,如下所示:
using (ProgressForm FPProgForm = new ProgressForm(TheUI))
{
FPProgForm.ShowDialog();
if (FPProgForm.DialogResult == DialogResult.OK)
{
// display results screen
}
}
在FPProgForm
构造函数中,我正在创建一个新的BackgroundWorker()
因此,每当我创建一个新对话框时,BackGroundWorker
应该是全新的
更新:根据请求,以下是整个进度表类:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace FPDWF
{
public partial class ProgressForm : Form
{
public delegate void RunFunctionDelegate();
RunFunctionDelegate FuncToRun { get; } // function to be run
FPDesktopWFUI TheUI { get; }
BackgroundWorker TheBackgroundworker; // for internal use only, like a viagra demo
public ProgressForm(RunFunctionDelegate funcToRun, FPDesktopWFUI theUI)
{
InitializeComponent();
FuncToRun = funcToRun;
TheUI = theUI;
TheBackgroundworker = new BackgroundWorker();
InitializeBackgroundWorker();
// subscription to event stuff here: http://stackoverflow.com/questions/14871238/report-progress-backgroundworker-from-different-class-c-sharp
TheUI.OnProgressUpdate += FPProgUpdate;
}
// Set up the BackgroundWorker object by
// attaching event handlers.
private void InitializeBackgroundWorker()
{
// background worker stuff here: https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
TheBackgroundworker.DoWork +=
new DoWorkEventHandler(TheBackgroundworker_DoWork);
TheBackgroundworker.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(TheBackgroundworker_RunWorkerCompleted);
TheBackgroundworker.ProgressChanged +=
new ProgressChangedEventHandler(TheBackgroundworker_ProgressChanged);
TheBackgroundworker.WorkerReportsProgress = true;
TheBackgroundworker.WorkerSupportsCancellation = true;
}
private void ProgressForm_Load(object sender, EventArgs e)
{
// progress bar stuff here: http://stackoverflow.com/questions/12126889/how-to-use-winforms-progress-bar
ui_progbar.Maximum = 100;
ui_progbar.Step = 1;
ui_progbar.Value = 0;
TheBackgroundworker.RunWorkerAsync();
}
private void ui_cancelbutton_Click(object sender, EventArgs e)
{
if (TheBackgroundworker.WorkerSupportsCancellation == true)
{
// Cancel the asynchronous operation.
TheBackgroundworker.CancelAsync(); // there really is no purpose to this as i can just set the contRunning flag I think
TheUI.contRunning = false; // i think this thread safe due to 'volatile flag', https://msdn.microsoft.com/en-us/library/7a2f3ay4(v=vs.100).aspx
resultLabel.Text = "Cancelling...";
}
}
// This event handler is where the time-consuming work is done.
private void TheBackgroundworker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
FuncToRun();
}
// This event handler updates the progress.
private void TheBackgroundworker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// something to do here?
}
// This event handler deals with the results of the background operation.
private void TheBackgroundworker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (TheBackgroundworker.CancellationPending == true) // if (e.Cancelled == true)
{
this.DialogResult = DialogResult.Cancel;
this.Close();
}
else if (e.Error != null)
{
this.DialogResult = DialogResult.Abort;
resultLabel.Text = "Error: " + e.Error.Message;
ui_viewres_btn.Text = "Close";
ui_viewres_btn.Enabled = true;
}
else
{
this.DialogResult = DialogResult.OK;
ui_viewres_btn.Enabled = true;
}
}
private void FPProgUpdate(string progText, double prog)
{
// utilizing this: http://stackoverflow.com/a/14871753/3661120
int intProg = Convert.ToInt32(prog * 100);
if (!TheBackgroundworker.CancellationPending)
{
TheBackgroundworker.ReportProgress(intProg); // doesn't really do anything at this point, but whatev
base.Invoke((Action)delegate
{
resultLabel.Text = progText;
ui_progbar.Value = intProg;
});
}
}
private void ui_viewres_btn_Click(object sender, EventArgs e)
{
this.Close(); // closes the window
}
}
}
更新2:即使我删除了有问题的backgroundworker.ReportProgress(intProg)代码>行,我仍然收到此错误:
其他信息:无法在服务器上调用Invoke或BeginInvoke
控件,直到创建窗口句柄为止
BackgroundWorker.ReportProgress
只能从执行DoWork
的线程内部调用。从您的代码中,它看起来像是FPProgUpdate
包含一个ReportProgress
,并且正在从某个线程调用,而不是从启动DoWorkBackgroundWorker的线程调用。ReportProgress
只能从执行DoWork
的线程内部调用。从您的代码中,它看起来像是FPProgUpdate
包含一个ReportProgress
,并且正在从启动DoWork的线程以外的某个线程调用。您检索此错误是因为您订阅了此事件:
TheUI.OnProgressUpdate += FPProgUpdate;
因此,FPProgUpdate
多次调用ReportProgress()
正如您已经注意到的,以下类似项不是必需的,您可以将其删除:
TheBackgroundworker.ReportProgress(intProg);
您检索此错误是因为您正在订阅此事件:
TheUI.OnProgressUpdate += FPProgUpdate;
因此,FPProgUpdate
多次调用ReportProgress()
正如您已经注意到的,以下类似项不是必需的,您可以将其删除:
TheBackgroundworker.ReportProgress(intProg);
谢谢马克在这方面的帮助。解决方案是,我需要从处置方法中的ui.on progressupdate
事件中取消订阅FPProgUpdate
,我必须覆盖该事件:
protected override void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
if (components != null)
{
components.Dispose();
}
// Dispose stuff here
TheUI.OnProgressUpdate -= FPProgUpdate;
}
disposed = true;
base.Dispose(disposing);
}
处置不会自动取消订阅,看起来是这样。感谢Marc在这方面的帮助。解决方案是,我需要从处置方法中的ui.on progressupdate
事件中取消订阅FPProgUpdate
,我必须覆盖该事件:
protected override void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
if (components != null)
{
components.Dispose();
}
// Dispose stuff here
TheUI.OnProgressUpdate -= FPProgUpdate;
}
disposed = true;
base.Dispose(disposing);
}
处置不会自动取消订阅,这似乎是。我认为问题出在其他地方。在哪里调用BackgroundWorker.ReportProgress()
?你能出示进度表吗?我想问题出在别的地方。在哪里调用BackgroundWorker.ReportProgress()
?可以显示ProgressForm吗?谢谢,但现在我收到另一条错误消息附加信息:在创建窗口句柄之前,无法对控件调用Invoke或BeginInvoke。
。谢谢,但现在我收到另一条错误消息附加信息:在创建窗口句柄之前,无法对控件调用Invoke或BeginInvoke。
(如下)谢谢,但现在我收到另一条错误消息附加信息:在创建窗口句柄之前,无法对控件调用Invoke或BeginInvoke。
。请尝试在ProgressForm的显示的事件中启动BackgroundWorker,而不是加载。这似乎太早了。好的,还有一个问题:TheUI
的实例正在调用FPProgUpdate。这并不像斯科特已经提到的那样好。最好在BackgroundWorkersProgressChanged
事件中更新UI(将代码从FPProgUpdate移动到那里)。但是在不知道ui的实现的情况下,我们无法告诉您一个正确的答案……这就是stack overflow post关于过程如何报告其进度的解决方案。还有其他建议吗?无论如何,我不明白为什么表单没有被处理。同样,它在我第一次运行它时仍然有效。感谢您的帮助。(如下)谢谢,但现在我收到另一条错误消息附加信息:在创建窗口句柄之前,无法对控件调用Invoke或BeginInvoke。
。请尝试在ProgressForm的Showed
事件中启动BackgroundWorker,而不是Load
。这似乎太早了。好的,还有一个问题:TheUI
的实例正在调用FPProgUpdate。这并不像斯科特已经提到的那样好。最好在BackgroundWorkersProgressChanged
事件中更新UI(将代码从FPProgUpdate移动到那里)。但是在不知道ui的实现的情况下,我们无法告诉您一个正确的答案……这就是stack overflow post关于过程如何报告其进度的解决方案。还有其他建议吗?无论如何,我不明白为什么表单没有被处理。同样,它在我第一次运行它时仍然有效。谢谢你的帮助。