WPF でプログレスバーを使う
アプリ内で時間のかかる処理を行う場合、プログレスバーを画面に表示することでユーザーはその進捗を直感的、視覚的に把握できるようになります。
何の表示もないまま時間のかかる処理を実行すると、画面が固まっているように見えてユーザーを不安にさせてしまいます。したがって重たい処理を行う時はプログレスバーなどで進捗を示してあげましょう。
WPFには標準のコントロールとして、ProgressBar が提供されています。ここではこのコントロールの使い方を見ていきます。
未定プログレスバー(マーキースタイル)
実行するタスクの処理量や時間が予測できないような場合(タスクの進行割合を数値で示せない場合)は、未定プログレスバーを使います。Windows だと マーキースタイルと呼ばれるようです。
上の画像のように、一定幅のバー内を繰り返し動くようなアニメーションのプログレスバーになります。これはタスクが現在進行形で処理中ということを意味します。
サンプルコード
xaml
<ProgressBar
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="200"
Height="20"
IsIndeterminate="True" />
最終行で指定している IsIndeterminate
プロパティを True にすることで繰り返しのアニメーションが表示されるようになります。
処理開始時にこのプログレスバーを表示し、時間のかかる処理が完了したらプログレスバーごと Visibility を変更して消すというような使い方をします。
進捗度を示すプログレスバー
ProgressBar
のプロパティ Value
に現在の進捗度を数値で設定することで、バーの緑色の部分の幅を変更できます。ここに進捗度をバインドしてやれば、進捗度に従ってアニメーションして見えるようになります。
こんな感じで進捗度に従ってバーの緑色が動きます。
サンプルコード
上で示した画像のように、ボタンを押したらタスクの処理を実行し、その進捗をプログレスバーに表示するようにします。
xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="300" Width="300">
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center">
<!-- プログレスバー -->
<ProgressBar
Width="200"
Height="20"
Minimum="0"
Maximum="100"
Value="{Binding Progress}"
/>
<Button Content="実行" Width="75" Margin="10" Click="Button_Click"/>
</StackPanel>
</Window>
ProgressBar の Minimum
, Maximum
は Value
がとりうる値の範囲(最小値と最大値)を設定します。ここでは 0~100 までの範囲としています。
Value
は進捗度を表す数値を設定します。ここではバインドしています。
サンプルなので、ほかのコードはすべてコードビハインドに書きます。
ではボタンクリック時のイベントを定義していきましょう。
xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
// 実行ボタン押下時のイベント
private async void Button_Click(object sender, RoutedEventArgs e)
{
var vm = this.DataContext as ViewModel;
await Task.Run(async () =>
{
while(vm.Progress < 100)
{
vm.Progress += 1;
await Task.Delay(10);
}
});
MessageBox.Show("タスクが完了しました。");
vm.Progress = 0;
}
}
// 進捗を表すための ViewModel
public class ViewModel : INotifyPropertyChanged
{
private int _Progress;
public int Progress
{
get { return this._Progress; }
set
{
this._Progress = value;
this.NotifyProperyChanged(nameof(this.Progress));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyProperyChanged(string name)
{
this.PropertyChanged?.Invoke(
this,
new PropertyChangedEventArgs(name)
);
}
}
ViewModel は単純に変更通知機能を実装した整数型のプロパティ Progress を持つだけの単純なクラスです。
実際の重たい処理にあたる部分は以下の箇所です。
await Task.Run(async () =>
{
while(vm.Progress < 100)
{
vm.Progress += 1;
await Task.Delay(10);
}
});
このコードは非同期で進捗度を100までカウントアップしています。1カウントするごとに 0.01秒のディレイを挟んでいます。
こうするることで Progress がカウントアップされるたびに、画面の ProgressBar の緑色の部分が更新されるようになります。
このタスクが完了するまで await するようにしており、進捗が100になるとメッセージボックスを表示しています。
もう一度動きを見てみましょう。
いい感じに動いていますね。実はこのままだと実行ボタンを何度も押せてしまうので、実運用にはもう少し制御が必要ですが、基本はこのようにして使います。
以上。
コメントを書く