2016-09-27 223 views
-1

我創建了一個Windows窗體程序,用於分解文件並將其組件發送到服務器。這些文件很大,所以我創建了一個progressBar,因此用戶不會在事務發生時凍結它。我想要做的是有一些機制,只有當所有線程完成而不會阻塞UI線程時纔會主動觸發(再次,因此平臺不會認爲它被凍結)。我能想到的最好的方式是被動地「等到真實」,但我覺得必須有更好的方式來做到這一點。我嘗試過嘗試創建一個事件或回調,但老實說,我剛剛結束時比我開始時更困惑。下面是我現在怎麼做這樣一個例子:如何在進度條完成時觸發事件

public partial class Program : Form 
    { 
     private readonly OpenFileDialog _ofd = new OpenFileDialog(); 
     public delegate void BarDelegate(); 
     private string _path; 

     private void button1_Click(object sender, EventArgs e) 
     { 
      if (_ofd.ShowDialog() != DialogResult.OK) return; 

      textBox1.Text = _ofd.SafeFileName; 
      _path = _ofd.FileName; 
     } 

     private void button2_Click(object sender, EventArgs e) 
     { 
      var allLinesFromFile = File.ReadAllLines(_path); 
      progressBar1.Minimum = 0; 
      progressBar1.Maximum = allLinesFromFile.Length; 

      Task.Factory.StartNew(() => Parallel.ForEach(allLinesFromFile, DoSomething)); 

      while (progressBar1.Value < progressBar1.Maximum) //there has to be a better way to do this... 
      { 
       MessageBox.Show("Please wait.", "Record Poster", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); 
      } 

      //some processes here which should only take place after all threads are complete. 

      var postingComplete = MessageBox.Show("The posting is complete!", "Record Poster", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); 
      if (postingComplete == DialogResult.OK) Environment.Exit(0); 
     } 

     private void DoSomething(string record) 
     { 
      //some string manipulation and server transactions here 

      BeginInvoke(new BarDelegate(() => progressBar1.Increment(1))); 
     } 
    } 
+3

你是爲進度條提供價值的人 - 所以當你達到100時,請調用你想做的方法。首先,你不需要TaskFactory。 –

+0

第三 - 有多少條線?看起來像顯示一個消息框會比處理本身花費更多的時間 –

+0

您可以編寫'ValueChanged'事件並檢查'Value == Maximum' – TaW

回答

1

爲嘗試使用微軟的Reactive Framework(NuGet「System.Reactive.Windows.Forms」)。那麼你的代碼變成:

private void button2_Click(object sender, EventArgs e) 
    { 
     var allLinesFromFile = File.ReadAllLines(_path); 
     progressBar1.Minimum = 0; 
     progressBar1.Maximum = allLinesFromFile.Length; 

     IDisposable subscription = 
      allLinesFromFile 
       .ToObservable() 
       .SelectMany(f => Observable.Start(() => DoSomething(f))) 
       .ObserveOn(this) 
       .Do(x => progressBar1.Value += 1) 
       .Subscribe(x => { },() => 
       { 
        var postingComplete = MessageBox.Show("The posting is complete!", "Record Poster", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); 
        if (postingComplete == DialogResult.OK) 
        { 
         Application.Exit(); 
        } 
       }); 
    } 

    private void DoSomething(string record) 
    { 
     System.Threading.Thread.Sleep(5); 
    } 

如果您需要停止這種早期然後就打電話subscription.Dispose()。我已經測試過了,它對我來說工作正常。

+0

我很欣賞答案,但是這似乎是在所有線程完成之前處理訂閱操作。有些計算應該只在所有線程完成後纔會發生,並且此解決方案將允許訂閱模塊在最後一個線程被觸發時但在它實際發佈到服務器之前運行。你可以這樣說,因爲如果你用一個大文件運行這個文件,你會看到在帖子到達結尾之前彈出「Posting complete」消息。這是我嘗試向ThreadPool添加方法調用時遇到的問題,這就是爲什麼我切換到了Parallel.Foreach。 –

+0

Parallel.Foreach阻止執行,直到所有線程完成,這正是我想要的,但不幸的是,它也阻止了UI的更新。因此我的困境。 –

+0

爲你增加了背景工作者的想法...祝你好運! –

0

你應該使用BackgroundWorker類,請參閱:How to use a BackgroundWorker?

並使用BackGroundWorker.RunWorkerComplete當線程完成

+0

我正在調查這是一個可能的解決方案。感謝您的建議。 –

-1

背景工人:

**Backgroundworker (System.ComponentModel)** 

BackgroundWorker loader = new BackgroundWorker(); 
    loader.DoWork += load_Specials_BW_Thread; 
     loader.WorkerReportsProgress = true; 
     loader.ProgressChanged += load_Special_Feeds_Progress_Changed; 
    private void load_Specials_BW_Thread(object sender, DoWorkEventArgs e) 
    { 

     int pctComplete = (int)Math.Floor(ptComplete * 100);//recs done/total recs 
     (sender as BackgroundWorker).ReportProgress(pctComplete); 
    } 

祝你好運!

相關問題