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();
}
}