我有一个Backgroundworker,它从数据库中收集大量数据。我想在线程上设置超时限制,这样如果在一段时间后它没有返回结果,则取消该过程。
我在启动BackgroundWorker的同时在主线程上启动了一个计时器。
如果我故意让BGW睡眠,计时器会过去并调用.Elapsed事件。然后取消后台工作程序,但是它没有成功完成我想要完成的其他操作,这些操作会更新GUI上的状态栏并抛出MessageBox。我不明白为什么不,有人可以帮忙吗?
故意设置超时和睡眠以进行测试。
/// <summary>
/// loads Assets by group ID
/// Populates Grid on asset listing page
/// </summary>
/// <param name="groupId"></param>
/// <param name="user"></param>
internal void PopulateGridAssetsByGroup(int groupId, User user)
{
//update statusbar
AfMainWindow.MainWindow.UpdateStatusBar("Loading Assets...");
//setup BG worker
populateGridAssetsWorker = new BackgroundWorker {WorkerSupportsCancellation = true, WorkerReportsProgress = false};
populateGridAssetsWorker.DoWork += populateGridAssetsWorker_DoWork;
populateGridAssetsWorker.RunWorkerCompleted += populateGridAssetsWorker_RunWorkerCompleted;
//setup timer which will cancel the background worker if it runs too long
cancelTimer = new Timer {Interval = 2000, Enabled = true, AutoReset = false};
cancelTimer.Elapsed += cancelTimer_Elapsed;
cancelTimer.Start();
populateGridAssetsWorker.RunWorkerAsync(groupId); //start bg worker
}
void cancelTimer_Elapsed(object sender, ElapsedEventArgs e)
{
populateGridAssetsWorker.CancelAsync();
cancelTimer.Stop();
AfMainWindow.MainWindow.UpdateStatusBar("Could not load assets, timeout error");
MessageBox.Show("Operation Timed Out\n\nThe Server did not respond quick enough, please try again",
"Timeout", MessageBoxButton.OK, MessageBoxImage.Exclamation, MessageBoxResult.OK);
AfMainWindow.MainWindow.Busy.IsBusy = false;
}
/// <summary>
/// when bg worker complete, update the AssetGrid on Asset Listing Page with results
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void populateGridAssetsWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
cancelTimer.Stop();
//my thread complete processing
}
/// <summary>
/// Perform the DB query and collect results for asset listing
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void populateGridAssetsWorker_DoWork(object sender, DoWorkEventArgs e)
{
var assetListByGroup = new List<AssetLinked>();
Thread.Sleep(5000);
if (populateGridAssetsWorker.CancellationPending)
{
return;
}
try
{
//My SQL actions
if (populateGridAssetsWorker.CancellationPending)
{
return;
}
}
catch (Exception ex)
{
Globals.AFWideSettings.GeneralErrorMessage(ex.Message);
}
}
答案 0 :(得分:2)
当您尝试从另一个线程更新GUI时,我假设您的cancelTimer_Elapsed
方法会无声地崩溃。如果没有调试Visual Studio设置为中断所有异常,有时很难找到后台线程中抛出的异常 - 您可以在菜单Debug > Exceptions
中设置并检查所有CLR异常。或者,您可以将方法体包装在try
块中,并将断点放在catch块中。
void cancelTimer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
populateGridAssetsWorker.CancelAsync();
cancelTimer.Stop();
AfMainWindow.MainWindow.UpdateStatusBar("Could not load assets, timeout error");
MessageBox.Show("Operation Timed Out\n\nThe Server did not respond quick enough, please try again",
"Timeout", MessageBoxButton.OK, MessageBoxImage.Exclamation, MessageBoxResult.OK);
AfMainWindow.MainWindow.Busy.IsBusy = false;
}
catch(Exception ex)
{
int breakpoint = 42;
}
}
我不确定是这种情况,但在我看来值得一试。