2010-12-16 14 views
1

我有一個WPF應用程序讀取文件並在數據庫中插入一些記錄的導入文件方法。WPF:如何調用Dispatcher.BeginInvoke *當隊列中沒有任何內容被調用時?

此方法運行在BackgroundWorker對象中。 我在Dispatcher.Invoke調用中更新了進度條。如果按原樣運行,導入200k條記錄需要1分鐘左右的時間,如果我只是沒有顯示任何進度,則只需要4到5秒!如果我使用Dispatcher.BeginInvoke,Background優先級,它需要相同的4到5秒,但進度條+計數器正在更新並需要大約1分鐘。所以,顯而易見,用戶界面是這裏的問題。

而另一個問題是我需要顯示一個進度,所以我在想如果有什麼辦法可以使用Dispatcher.BeginInvoke,但首先檢查隊列上是否有任何東西,如果是這樣,我只是跳過它,這會表現如下:第一秒完成1%,2秒後完成50%,第四秒完成100%)。

對此有何幫助?

謝謝!!!

回答

2

不可能說沒有看到代碼,但

我有一個進度條Dispatcher.Invoke呼叫

裏面爲什麼要更新?這就是ReportProgress的用途。

如果我不得不猜測(而且我這樣做),我會說你經常報告進度。例如,不要在每條記錄之後報告進度,但是在批量100或者其他之後不報告進度。

2

問題是您的回調在Dispatcher上排隊。每一個都會導致屏幕重新繪製,並且由於它們處於後臺優先級,下一個將在等待重新繪製完成之前處理,因此每個回調都需要重新繪製一次,這可能會很慢。

不要試圖等到調度程序隊列中什麼都沒有,只需等到上一個進度回調已經處理完畢後再發佈一個新回調。這將確保您一次不會有多個活動,所以他們無法排隊。

您可以通過設置一個標誌,當您發佈回調並清除處理後清除它。例如:

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    var pending = false; 
    for (int i = 0; i < 1000000; i++) 
    { 
     // Do some work here 
     // ... 
     // Only report progress if there is no progress report pending 
     if (!pending) 
     { 
      // Set a flag so we don't post another progress report until 
      // this one completes, and then post a new progress report 
      pending = true; 
      var currentProgress = i; 
      Dispatcher.BeginInvoke(new Action(() => 
      { 
       // Do something with currentProgress 
       progressBar.Value = currentProgress; 
       // Clear the flag so that the BackgroundWorker 
       // thread will post another progress report 
       pending = false; 
      }), DispatcherPriority.Background); 
     } 
    } 
} 
2

我只想更新後臺線程的進度計數器(只寫入計數器),並有UI讀取(只讀)定時器每500毫秒左右... ...有沒有理由更新比這更快。另外,因爲一個線程只寫,一個只讀,所以不需要線程問題。代碼變得更簡單,更清潔,更易於維護。

-Chert Pellett

0

我剛剛解決了同樣的情況,但使用BeginInvoke返回的對象,我認爲這是相當優雅的呢!

DispatcherOperation uiOperation = null; 
while (…) 
{ 
    … 
    if (uiOperation == null || uiOperation.Status == DispatcherOperationStatus.Completed || uiOperation.Status == DispatcherOperationStatus.Aborted) 
    { 
     uiOperation = uiElement.Dispatcher.BeginInvoke(…); 
    } 
} 

進度條變得有點碎片(不那麼光滑),但它蒼蠅。就我而言,代碼使用StreamReader.ReadLine()從文本文件逐行解析。讀完每行之後更新進度條會導致讀取操作在進度條甚至填滿一半之前完成。使用同步Dispatcher.Invoke(…)會使整個操作速度降至100 KiB/s,但進度條會準確跟蹤進度。使用上面的解決方案,我的應用程序只需3次進度條更新即可完成分析8,000 KiB的工作。

與使用BackgroundWorker.ReportProgress(…)的一個區別是進度條可以在長時間運行的操作中顯示更精細的細節。 BackgroundWorker.ReportProgress(…)僅限於報告從0%到100%的增量1%的進度。如果您的進度條代表100多個操作,則需要更精細的值。當然,也可以通過不使用percentProgress參數並將userState改爲BackgroundWorker.ReportProgress(…)來實現。

相關問題