2009-07-01 14 views
12

私のプログラム[C#+ winforms]にあります。私はプログレスバー& listviewを持っています。Winformsプログレスバーが更新されない(C#)

私はいくつかの操作を実行して、&を実行してから、リストビューでデータを更新しています。追加されたレコードの数は、ProgressBar.valueプロパティの値です。私がここで望んでいるのは、プログレスバーの価値によると、その進行状況を示すはずです。ただし、プログレスバーは更新されません。メソッド実行の進行状況バーの最後にのみ、全体の進捗状況が表示されます。つまり、100%

この点についてお手伝いできますか?

おかげで、 アミット

+2

ため

おかげで、私はここに答えることがC#の程度は十分知っているが、Javaで、それは別のスレッドを持っている必要がありますか、他あなたがこれと同じ動作を取得しますスイングはありません。 – Chet

答えて

26

あなたはUIスレッドをブロックしているようですね - あなたがどんな絵を行うためのシステムをリリースしていない、すなわち。

ハッキーな答えはコードにApplication.DoEvents()を注入することですが、これは危険であり、再突入などの問題があります。それはちょっとハッキーです。

BackgroundWorkerの処理を行うことをお勧めします。UIスレッドに定期的に切り替えて(Control.Invoke)更新します。ListViewに多くの項目を追加する場合は、これが難しいかもしれません。

全例(あなたはUIの更新バッチにしたいかもしれませんが - ない行時):

using System; 
using System.ComponentModel; 
using System.Threading; 
using System.Windows.Forms; 

class MyForm : Form 
{ 
    BackgroundWorker worker; 
    ListView list; 
    Button btn; 
    ProgressBar bar; 
    public MyForm() 
    { 
     Text = "Loader"; 
     worker = new BackgroundWorker(); 
     worker.WorkerReportsProgress = true; 
     worker.ProgressChanged += worker_ProgressChanged; 
     worker.DoWork += worker_DoWork; 
     worker.RunWorkerCompleted += worker_RunWorkerCompleted; 
     list = new ListView(); 
     list.Dock = DockStyle.Fill; 
     Controls.Add(list); 
     btn = new Button(); 
     btn.Text = "Load"; 
     btn.Dock = DockStyle.Bottom; 
     Controls.Add(btn); 
     btn.Click += btn_Click; 
     bar = new ProgressBar(); 
     bar.Dock = DockStyle.Top; 
     Controls.Add(bar); 
    } 

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     btn.Enabled = true; 
    } 

    void btn_Click(object sender, EventArgs e) 
    { 
     worker.RunWorkerAsync(); 
     btn.Enabled = false; 
    } 


    void worker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     for (int i = 0; i < 100; i++) 
     { 
      string newRow = "Row " + i.ToString(); 
      worker.ReportProgress(i, newRow); 
      Thread.Sleep(100); 
     } 
    } 

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     list.Items.Add((string)e.UserState); 
     bar.Value = e.ProgressPercentage; 
    } 

    [STAThread] 
    static void Main() 
    { 
     Application.EnableVisualStyles(); 
     Application.Run(new MyForm()); 
    } 
} 
0

ProgressBar.Valueは0から100

私の推測の間でなければなりませんさあなたの問題はGUIスレッド上でListViewを更新しているということです。つまり、ProgressBar.Valueプロパティを変更した後にApplication.DoEvents()に電話する必要があります。

BackgroundWorkerで実行し、ProgressChangedイベントを使用してProgressBarの更新を処理するのが最適です。

Here's another questionほぼ同じトピックです。

+0

プログレスバーの値は0〜100の間でなければならないのはなぜですか? – Hemant

+0

パーセントを扱うときに利便性以外の理由はありません。 –

+0

progressBar1.Maximum = [int]を設定すると、progressbar maxを大きくすることができます。[int]は整数です。 –

3

Marcは言ったように、長期間の計算を行うために新しいスレッドをスピンオフする必要があります。そうすれば、完了したパーセンテージを変更するたびに、ユーザーインターフェイスのスレッド(すべての画面更新を行う必要があるスレッド)がプログレスバーを再描画できます。

UIスレッドがインターフェイスを更新できることに注意することが重要です。したがって、別のスレッドで実行した後は、UIの変更がUIスレッド上で処理されるように余分なフープを実行する必要があります。実行中のスレッドが不明な場合は、InvokeRequiredの値を確認して(実際のクラスがSystem.Windows.Formの場合)、UIスレッドであるかどうかを確認できます。

UIスレッドでコマンドを処理するには、Control.Invoke()関数を使用して、作業中のコントロールのUIスレッドで更新が処理されていることを確認します。

下のサンプルコードでは、デリゲート関数の型を作成し、呼び出された関数を事前に宣言しています。私はC#3.5のすばらしい関数を使っていませんでしたが、同じことをするラムバ式。

private void bCreateInvoices_Click(object sender, EventArgs e) 
    { 
     BackgroundWorker worker = new BackgroundWorker(); 
     worker.DoWork += new DoWorkEventHandler(CreateInvoices); 
     worker.RunWorkerAsync(this); 
    } 

// Here is the long running function that needs to update the progress bar 
public void CreateInvoices(object sernder, DoWorkEventArgs e) 
    { 
     int totalChecked = CountCheckedServiceOrders(); 
     int totalCompleted = 0; 

     foreach (...data to process...) { 
      totalCompleted++; 
      if (InvokeRequired) { 
       Invoke(new Change(OnChange), "status text", 
         totalCompleted, totalChecked);     
      } 
     } 
    } 

    // this code updates the status while a background thread works 
    private delegate void Change(string status, int complete, int total); 
    private void OnChange(string status, int complete, int total) 
    { 
     if (status == null) { 
      progressBar.Visible = false; 
      lStatus.Text = "Task complete"; 
      progressBar.Value = 0; 
     } else { 
      progressBar.Visible = true; 
      progressBar.Minimum = 0; 
      progressBar.Maximum = total; 
      progressBar.Value = complete; 
      lStatus.Text = status; 
     } 

    } 

いくつかの詳細はMSDN Control.InvokeRequired manual pageMSDN Control.Invoke manual pageを見てみましょう。

4

本当に申し訳ありません友達、

実は、私はProgressBar.valueフィールドに値をassigingが、didntの使用update()メソッドました。私はそれを使用した&私の問題は解決した。すべての返信

関連する問題