У меня есть программа очистки веб-страниц.В главной форме вы можете выбрать веб-сайт и клиента и нажать кнопку «Перейти», и он запустит поток BackgroundWorker, который использует WebRequest и HTMLAgilityPack для обработки серии запросов для SiteX и ClientX, причем каждый запрос состоит из нескольких страниц.Каждый поток BackgroundWorker имеет проверки, которые выполняются, и если он сталкивается с проблемой, он выдает диалоговое окно для пользователя, чтобы прервать поток, отменить запрос, проигнорировать ошибку или (если запустить из IDE) ввести в код.Я хочу, чтобы это диалоговое окно содержало элемент управления WebBrowser для отображения красиво оформленной HTML-страницы.Однако, поскольку он вызывается из потока BackgroundWorker, я получаю исключение «текущий поток не находится в однопоточной квартире».
Вот функция, которая создает диалоговое окно:
protected bool ValidatePage( bool pagePasses, string msg ) {
if ( pagePasses == false ) {
AbortIgnoreSuspend ais = new AbortIgnoreSuspend( responsehtml, msg );
ais.ShowDialog();
switch ( ais.DialogResult ) {
case DialogResult.Abort: // Aborts entire thread
Abort = true;
worker.CancelAsync();
return false;
case DialogResult.Cancel: // Aborts this case
Abort = true;
return false;
case DialogResult.Ignore: // Ignore and continue
return true;
case DialogResult.Retry: // Debug
Debug.Assert( false, "Suspending Thread" );
return true; // Will return you to calling thread and allow you to continue
default:
return true;
}
}
return true;
}
Я нашел примеры, когда запуск Thread () с ApartmentState, установленным в ApartmentState.STA, мог бы создать мой WebBrowser, поэтому я сделал следующую корректировку кода:
protected bool ValidatePage( bool pagePasses, string msg ) {
if ( pagePasses == false ) {
bool setAbort = false;
bool assertError = false;
bool cancelWorker = false;
bool returnContinue = true;
Thread th = new Thread( () => {
AbortIgnoreSuspend ais = new AbortIgnoreSuspend( responsehtml, msg );
ais.ShowDialog();
switch ( ais.DialogResult ) {
case DialogResult.Abort: // Aborts entire thread
setAbort = true;
cancelWorker = true;
returnContinue = false;
break;
case DialogResult.Cancel: // Aborts this case
setAbort = true;
returnContinue = false;
break;
case DialogResult.Ignore: // Ignore and continue
returnContinue = true;
break;
case DialogResult.Retry: // Debug
assertError = true;
returnContinue = true; // Will return you to calling thread and allow you to continue
break;
default:
returnContinue = true;
break;
}
} );
th.SetApartmentState( ApartmentState.STA );
th.Start();
th.Join();
Abort = setAbort;
Debug.Assert( !assertError, "Suspending thread for debugging" );
if ( cancelWorker ) { worker.CancelAsync(); }
return returnContinue;
}
return true;
}
Это, похоже, работает(Я тестировал с одним BackgroundWorker), однако я вполне уверен, что из-за недостатка опыта работы с потоками я допустил некоторые ошибки в безопасности потоков.Что я сделал не так, что я пропустил?