如何停止Backgroundworker并关闭表单?
我想完全停止BackgroundWorker DoWork()过程,同时运行关闭窗体。如何停止Backgroundworker并关闭表单?
我已经应用了下面的代码,但在“this.Invoke”中会引发错误:“调用或BeginInvoke无法在控件上调用,直到窗口句柄被创建。”同时形成关闭。
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
var dt_Images = db.Rings.Select(I => new { I.PaidRs, I.TypeID, I.RingID, I.CodeNo, Image = Image.FromStream(new MemoryStream(I.Image.ToArray())) }).OrderByDescending(r => r.TypeID);
foreach (var dr in dt_Images.ThenByDescending(r => r.RingID).ToList())
{
BTN = new Button();
BTN.TextImageRelation = TextImageRelation.TextAboveImage;
BTN.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
BTN.AutoSize = true;
BTN.Name = dr.RingID.ToString();
BTN.Image = dr.Image;
BTN.Text = dr.CodeNo.ToString() + " " + dr.TypeID.ToString();
this.Invoke(new MethodInvoker(delegate { if (backgroundWorker1 != null) flowLayoutPanel1.Controls.Add(BTN); else return; }));
BTN.Click += new EventHandler(this.pic_Click);
this.Invoke(new MethodInvoker(delegate { if (backgroundWorker1 == null) txt_pcs.Text = flowLayoutPanel1.Controls.Count.ToString(); else return;}));
}
}
private void Form_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyData == Keys.Escape)
{
backgroundWorker1.CancelAsync(); //backgroundworker doesnt stop here
backgroundWorker1 = null; //it still invokes the delegate
this.Dispose();
}
}
如何解决此错误?
请帮帮我。
实际的问题是,在后台线程调用Invoke
之前,没有办法安全地检查表单是否正在关闭。
要做到这一点,你可以做的是推迟关闭一点,直到后台线程有机会退出主循环。
首先,声明两个标志和一个锁对象:
private volatile bool _closeRequest = false;
private volatile bool _workerStopped = false;
private readonly object _lock = new object();
然后,当你想关闭的形式,只需拨打Close
:
private void Form_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyData == Keys.Escape)
{
Close();
}
}
里面FormClosing
,检查是否劳动者已停止。这部分必须是显示器内部,以防止在后台线程只是被完成了比赛条件(即确保_workerStopped
和_closeRequest
是原子更新):
protected override void OnFormClosing(FormClosingEventArgs e)
{
lock (_lock)
{
// if not stopped
if (!_workerStopped)
{
// delay closing
e.Cancel = true;
// notify worker
_closeRequest = true;
}
}
base.OnFormClosing(e);
}
最后,在你的后台线程,实际关闭如果需要的形式:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
foreach (var dr in GetImages())
{
if (_closeRequest)
break;
// ... do stuff
}
}
finally
{
lock (_lock)
{
// notify we stopped
_workerStopped = true;
// if closing was postponed, close now
if (_closeRequest)
BeginInvoke(new MethodInvoker(Close));
}
}
}
里面你必须开始处理下一个图像之前要检查你的backgroundWorker1.CancellationPending
方法的DoWork。
在允许用户关闭表单之前,您必须等待处理完最后一张图像。
有关如何使用CancellationPending
和Cancel
性能comlete例子中看到this MSDN example
我也使用过MSDN的例子,但是也出现过同样的问题@ Philip Fourie – Tulsi 2012-03-29 08:57:15
你必须注意你的工人里面的取消请求。像
private void DoWork(object sender, DoWorkEventArgs e)
{
var worker = sender as BackgroundWorker;
while (!worker.CancellationPending)
{
…
}
if (worker.CancellationPending)
{
e.Cancel = true;
}
}
这里有一个简单的程序,我想,一定会给你的同时BackgroundWorker
运行如何采用这样的形式的关闭的护理的想法:
int i = 0;//This is to show progress.
bool cancel;//This is to notify RunWorkerCompleted to Close() the Form if needed.
public Form1()
{
InitializeComponent();
FormClosing += Form1_FormClosing;
backgroundWorker1.WorkerSupportsCancellation = true;
backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
backgroundWorker1.RunWorkerAsync();
}
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Since this is executed on the main thread - it is not (as far as I know) going to "race" against the FormClosing.
if (cancel) Close();
else Text = "Done";
}
void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (backgroundWorker1.IsBusy)
{
cancel = true;
backgroundWorker1.CancelAsync();
e.Cancel = true;
}
}
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.CancelAsync();
}
//This is executed on a separate thread:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (!backgroundWorker1.CancellationPending)
{
Invoke((Action)(() => Text = (i++).ToString()));
Thread.Sleep(1000);
}
e.Cancel = true;
}
为什么选择的AutoResetEvent在backgroundWorker1。 CancelAsync()?有没有好处?只是好奇。 – RvdK 2012-03-29 08:04:59
@PoweRoy:你说得对,第一部分也可以通过调用'CancelAsync'并在worker方法内轮询'BackgorundWorker.CancellationPending'完成。这只是稍微更通用一些,并且在将简单的后台线程用作工作人员时可以工作。 – Groo 2012-03-29 08:08:30
使用此方法,但在此过程中“_workerStopped.WaitOne();”光标正在等待。 @Groo – Tulsi 2012-03-29 08:54:39