2009-09-24 7 views
15

私はこのような問題があります:C#Winform ProgressBarとBackgroundWorker

私はMainFormという名前のフォームを持っています。私はこのフォーム上で行われるべき長い操作を持っています。

この長い操作が行われている間、私はMainFormの上に名前付きProgressFormから別のものを表示する必要があります。

プログレスフォームには進行状況バーがあります。長い操作が行われている間は更新が必要です。

ロング操作が完了したら、ProgressFormを自動的に閉じます。

私は、次のようないくつかのコードを書かれている:

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Windows.Forms; 
using System.Threading; 

namespace ClassLibrary 
{ 
    public class MyClass 
    { 
     public static string LongOperation() 
     { 
      Thread.Sleep(new TimeSpan(0,0,30)); 

      return "HelloWorld"; 
     } 
    } 
} 

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 

namespace BackgroungWorker__HelloWorld 
{ 
    public partial class ProgressForm : Form 
    { 
     public ProgressForm() 
     { 
      InitializeComponent(); 
     } 

     public ProgressBar ProgressBar 
     { 
      get { return this.progressBar1; } 
      set { this.progressBar1 = value; } 
     } 
    } 
} 

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 

using ClassLibrary; 

namespace BackgroungWorker__HelloWorld 
{ 
    public partial class MainForm : Form 
    { 
     ProgressForm f = new ProgressForm(); 

     public MainForm() 
     { 
      InitializeComponent(); 
     } 

     int count = 0; 
     private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 
     { 
      if (f != null) 
      { 
       f.ProgressBar.Value = e.ProgressPercentage; 
      } 

      ++count; 
     } 

     private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      if (e.Cancelled) 
      { 
       MessageBox.Show("The task has been cancelled"); 
      } 
      else if (e.Error != null) 
      {     
       MessageBox.Show("Error. Details: " + (e.Error as Exception).ToString()); 
      } 
      else 
      { 
       MessageBox.Show("The task has been completed. Results: " + e.Result.ToString()); 
      } 
     } 


     private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
     { 
      if (f == null) 
      { 
       f = new ProgressForm(); 
      } 

      f.ShowDialog(); 

      //backgroundWorker1.ReportProgress(100); 

      MyClass.LongOperation(); 

      f.Close(); 
     } 

     private void btnStart_Click(object sender, EventArgs e) 
     { 
      backgroundWorker1.RunWorkerAsync(); 
     } 

     private void btnCancel_Click(object sender, EventArgs e) 
     { 
      backgroundWorker1.CancelAsync(); 

      this.Close(); 
     } 
    } 
} 

私はプログレスバーを更新するための方法を見つけることではないのです。

私はbackgroundWorker1.ReportProgress()をどこに置くべきですか、どうすればいいですか?

MyClassに変更を加えてはいけません。私のアプリケーションのこの層で何が起こるか、またはどれくらいの時間がかかるかはわかりません。

誰でも手伝ってもらえますか?

答えて

12

1つの問題は、30秒間寝ていることです。通常、長時間実行されているタスク内のさまざまな時点でReportProgressに電話します。これを実証するために、コードを1秒間スリープするように変更することもできますが、スリープを終了するたびにReportProgressを呼び出すことができます。

別の問題は、ProgressFormの背景スレッドに表示していることです。 UIスレッドで開始する必要がありますが、バックグラウンドワーカーのProgressChangedイベントをそのスレッドにフックしてください。その後、バックグラウンドワーカーが進行状況を報告すると、進捗状況が更新されます。

+0

MyClassに変更を加えてはいけません。 Coz、私は私のアプリのこの層で何が起こるかわからない。 – anonymous

+6

その後、進捗状況を正確に報告することはできません。つまり、ProgressFormにタイマーを追加して毎秒プログレスバーを増やすことができますが、それは幻影に過ぎません。 *実際の進捗状況を知る方法がない場合は、プログレスバーはどれくらい便利ですか? –

2

ReportProgressは、あなたの「働く」方法で呼び出さなければならないメソッドです。 このメソッドは 'ProgressChanged'イベントを発生させます。

フォームでは、イベントハンドラをProgressChangedイベントに関連付けることができます。そのイベントハンドラーの中で、プログレスバーの位置を変更することができます。 イベントハンドラをRunWorkerCompletedイベントにアタッチすることもできます。そのイベントハンドラ内では、プログレスバーを含むフォームを閉じることができます。

+0

これは私が推測する一般的な解決策です。 Plzは再び問題を読んだ。 – anonymous

2

あなたがあなたがワーカースレッドをキャンセルできるようにしたい場合は、バックグラウンドワーカーは、ProgressChangedイベントと

backgroundWorker1.WorkerSupportsCancellation = true; 

を上げたい場合は

backgroundWorker1.WorkerReportsProgress = true; 

を設定する必要が注目されるべきです。

他の人によると、UIスレッドでf.ShowDialog()を実行し、ProgressChangedを使用してProgressWindowを更新します。

ProgressFormを自動的に閉じるには、backgroundWorker1_RunWorkerCompletedでfを呼び出します。閉じる();つまり、長い操作が完了し、ウィンドウを閉じることができます。

+0

UIスレッドからProgressWindowを呼び出す利点は何ですか? – anonymous

0

ここで必要なのは、メインフォーム全体をクラスに渡すのではなく、単にあなたのBackgroundWorkerのインスタンスを渡すことです。あなたのMyClass.MyMethod()あなたが進捗計算を行うと、単にあなたのメインのUIフォームにプログレスバーやその他もろもろを更新するためにworker.ReportProgress(int percentage)イベントを引き上げるで

private void bgWorker_DoWork(object sender DoWorkEventArgs e) 
{ 
    // Get the BackgroundWorker that raised this event 
    BackgroundWorker worker = sender as BackgroundWorker; 

    // And now you just send worker to whatever class you need like so: 
    bgArgs args = e.Argument as bgArgs; 
    MyClass objMyClass = new MyClass(); 

    MyClass.MyMethod(strValue, args.Option, worker); 

    // Do something based on return value. 
} 

そして:あなたはそうのような背景の労働者として送信者をキャストする必要があります!

これは完全に動作するはずです。

詳細については、このMSDNの記事を参照してください。CalculateFibonacciは、メインフォームのUIに更新を送信するカスタムクラスであるため、フィボナッチの例を参照してください。

詳細については、MSDN BackgroundWorker Classを参照してください。