2009-07-28 58 views
9

我正在使用C#和WPF,兩者都很新穎。如何在繁忙循環中顯示進度?

我有一個循環,從外部來源讀取大量的數據。該過程大約需要20秒,我想向用戶顯示進度。我不需要任何花哨的進度條,所以我選擇在標籤中繪製我的進度,標籤上會顯示「Step 1/1000」,然後更改爲「Step 2/1000」等。

我的代碼看起來像這個:

// "count" is the number of steps in the loop, 
// I receive it in previous code 

String countLabel = "/"+count.ToString(); 

for (i = 0; i < count; i++) 
{ 
    ... do analysis ... 
    labelProgress.Content = "Step "+i.ToString()+countLabel 
} 

但是,在分析過程中,屏幕「卡住」,進度不顯示爲前進。我理解我在C++中的這種行爲,我可能會有一個單獨的線程顯示進度條從循環接收通知,或某種形式的重繪/刷新,或強制窗口/應用程序處理其消息隊列。

什麼是在C#中做到這一點的正確方法?我不依賴於標籤,因此,如果有一個簡單的進度條彈出畫面,我可以代替使用這個標籤也將是巨大的......

感謝

+0

這可能是幫助你,** 100%測試** http://stackoverflow.com/a/42995210/6863414 – 2017-04-06 03:53:08

回答

11

移動工作再上一個BackgroundWorker和使用ReportProgress方法。

for (i = 0; i < count; i++) 
{ 
    ... do analysis ... 
    worker.ReportProgress((100 * i)/count); 
} 

private void MyWorker_ProgressChanged(object sender, 
    ProgressChangedEventArgs e) 
{ 
    taskProgressBar.Value = Math.Min(e.ProgressPercentage, 100); 
} 
+0

是線程安全的嗎? – 2009-07-28 15:10:42

+1

是的,應該是。您的後臺工作人員只在一個線程中進度欄更新只在UI線程上。如果UI線程嘗試更新值,則除UI線程之外的任何其他線程都會引發異常。所以你用這種方法保證線程安全。 – user7116 2009-07-28 15:13:03

2

由於當前線程的優先級高於最終設置標籤的UI線程,所以UI未更新。所以,直到你的線程完成你的東西,它會最終更新你的標籤。

我們是幸運的,對每一個WPF控件,可以讓你啓動一個新的線程與其他優先級的調度屬性..

labelProgress.Dispatcher.Invoke(DispatcherPriority.Background, 
        () => labelProgress.Content = string.Format("Step {0}{1}", i, countLabel)); 

這火起來在後臺線程,並會得到這份工作完成了!你也可以嘗試其他DispatcherPriority選項

PS我也冒昧地添加一個匿名方法和解決您的字符串解析有點..希望你不介意..

3
//Create a Delegate to update your status button 
    delegate void StringParameterDelegate(string value); 
    String countLabel = "/" + count.ToString(); 
    //When your button is clicked to process the loops, start a thread for process the loops 
    public void StartProcessingButtonClick(object sender, EventArgs e) 
    { 
     Thread queryRunningThread = new Thread(new ThreadStart(ProcessLoop)); 
     queryRunningThread.Name = "ProcessLoop"; 
     queryRunningThread.IsBackground = true; 
     queryRunningThread.Start(); 
    } 

    private void ProcessLoop() 
    { 
     for (i = 0; i < count; i++) 
     { 
      ... do analysis ... 
      UpdateProgressLabel("Step "+i.ToString()+countLabel); 
     } 
    } 

    void UpdateProgressLabel(string value) 
    { 
     if (InvokeRequired) 
     { 
      // We're not in the UI thread, so we need to call BeginInvoke 
      BeginInvoke(new StringParameterDelegate(UpdateProgressLabel), new object[] { value }); 
      return; 
     } 
     // Must be on the UI thread if we've got this far 
     labelProgress.Content = value; 
    } 
相關問題