Реальная проблема в том, что нет способа безопасно проверить, закрыта ли форма, перед вызовом 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));
}
}
}