Last Updated 2011/09/21
ProgressBar コントロールにはバグがあります。Microsoft はバグとは認めないかもしれませんが、バグ同然であることは確実です。
ProgressBar コントロールをテストした人は分かると思いますが、バーを進捗させるために Value プロパティを設定してもコントロールは反応しません。このページではこの問題を解決します。
プログレスバーコントロールは、ステータスバーコントロール内に配置することが多いので、それを前提として説明します。次のコードではステータスバーを 3 つの区画に分け、2 番目の区画にプログレスバーを配置するものです。プログレスバーはデザイン時は非表示にしておいて、必要になった時点で表示状態にします。
<StatusBar> <StatusBarItem Name="statusItem1" Content="" Width="140" DockPanel.Dock="Right" /> <Separator DockPanel.Dock="Right" /> <StatusBarItem Name="statusItem2" Width="140" DockPanel.Dock="Right"> <ProgressBar Name="progressBar" Visibility="Hidden" Width="134" Height="16" /> </StatusBarItem> <Separator DockPanel.Dock="Right" /> <StatusBarItem Name="statusItem3" Content="" /> </StatusBar>
以下は、プログレスバーを起動する分離コードです。
private void button1_Click(object sender, RoutedEventArgs e) { progressBar.Maximum = 20; progressBar.Minimum = 0; progressBar.Value = 0; progressBar.Visibility = Visibility.Visible; // 表示状態にする Mouse.SetCursor(Cursors.Wait); for (int i = 0; i < 20; ++i) { Thread.Sleep(200); // 実際に処理するコード progressBar.Value += 1; // プログレスバーの進捗状況を進める } progressBar.Visibility = Visibility.Hidden; // 非表示にする Mouse.SetCursor(Cursors.Arrow); }
これでいいはずなので、アプリケーションを起動するとプログレスバーが表示されないことに気付くはずです。私はハッキリ言っておきます。これはバグです。Microsoft は認めないかもしれませんが。
つまり、Value プロパティの変化にともなってコントロールの状態が変化することを期待されるコントロールが期待通りの動作をしないのはどう考えてもおかしい。では、その解決策は。
System.Windows.Forms.Application クラスには DoEvents メソッドがあって、こういう場合のために用意されています。そこで、上記のコードに手を加えれば問題は解決です。
for (int i = 0; i < 20; ++i) { Thread.Sleep(200); // 実際に処理するコード progressBar.Value += 1; // プログレスバーの進捗状況を進める System.Windows.Forms.Application.DoEvents(); // ← 追加 }
WPF アプリケーションで System.Windows.Forms.Application クラスの DoEvent メソッドを使うことに抵抗があるかもしれませんが、これで問題が解決することは間違いありません。
カスタムコントロールを作る手もあります。以下は、OnValueChanged メソッドをオーバーライドしただけのものですが、これで十分目的を達成できます。
public class ProgressBarEx : ProgressBar { public ProgressBarEx() { } protected override void OnValueChanged(double oldValue, double newValue) { base.OnValueChanged(oldValue, newValue); System.Windows.Forms.Application.DoEvents(); } }