2013-01-24 67 views
2

我有一個Backgroundworker,它從數據庫中收集大量數據。我想在線程上設置一個超時限制,這樣如果它在設定的時間量之後沒有返回結果,進程將被取消。Timer Elapsed Event不執行所有操作

我在啓動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

和反對票是爲了什麼? – Damo

+1

+1來取消downvote。對我來說似乎是一個合理的問題。 – PeteH

+0

這似乎是一個斷點的主要候選人,大概你已經做到了這一點?那麼你是說你點擊了MessageBox.Show ....但是沒有收到消息框? – PeteH

回答

2

想,當你嘗試更新從另一個線程的GUIcancelTimer_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; 
    } 
} 

我不確定是這種情況,但在我看來這是值得一試的。

+0

啊。做到了這一點,並添加了一個調試輸出到catch。我們有一個「調用線程不能訪問這個對象,因爲不同的線程擁有它。」但是這個事件肯定在主線上? – Damo

+1

哦... http://stackoverflow.com/questions/1435876/do-c-sharp-timers-elapse-on-a-separate-thread – Damo

+0

太棒了,所以你已經找到了問題。 'Timer'實際上使用更多的(ThreadPool)線程 - 一個用於定時器本身,至少一個用於'Elapsed'處理程序。所以事件不會在主線程中被觸發,您將不​​得不想出一個機制將GUI相關的代碼移回主線程。 –

相關問題