ProgressBar(プログレスバー)とは?
ProgressBarとは時間がかかる処理を非同期でさせている最中に,進捗状況を画面に表示するためのコントロールです。
主なプロパティ
- 進捗状況をValueに設定します。
- 最小値をMinimum,最大値をMaximumに設定します。パーセントで表示する場合は0から100で設定します。ファイル数等,処理の最大値がわかっている場合はその値を表示することで,どの程度作業が終わっているのかがユーザーに分かりやすくなります。
主なイベント
ValueChanged
Valueが変更されたときに通知されるので,このタイミングでTextBlockのTextプロパティに文字を設定することで,プログレスバーの目盛りだけではなく,文字でも表示することができるので,よりユーザーに分かりやすくなります。
表示形式
最初の画像で示している通り,主な表現の方法は3パターンあります。
パターン1:プログレスバーとテキストを別で表示する
この方法が一番簡単で一般的です。プログレスバーの周りにTextBlockなどを設置して,プログレスバーとテキスト表示を別で表示します。もちろんプログレスバー単体での表示も可能ですが,その場合,ユーザーは大体の値しか把握できなくなります。
<ProgressBar x:Name="AProgressBar" Margin="25,0,0,0" Height="30" Width="180" Minimum="0" Maximum="100" HorizontalAlignment="Left" ValueChanged="AProgressBar_ValueChanged" /> <TextBlock x:Name="ATextBlock" Margin="10,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" Text="xxx" Width="50" FontSize="20"/> <Button x:Name="AButton" Margin="10,0,0,0" Click="AButton_Click" Height="30" Width="60" Content="Run"/> </StackPanel>
public MainWindow() { InitializeComponent(); ATextBlock.Text = AProgressBar.Value.ToString() + "%"; } private void AProgressBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { ATextBlock.Text = AProgressBar.Value.ToString() + "%"; } private void AButton_Click(object sender, RoutedEventArgs e) { Task.Run(() => { for (int i = 0; i < 10; i++) { System.Threading.Thread.Sleep(500); Application.Current.Dispatcher.Invoke(() => { AProgressBar.Value += 10; }); } }); }
- AButton_Clickの中では,時間のかかる処理を作るために, 500ミリ秒のSleepを10回実施しています。
- Sleep 1回実施されるたびにProgressBarのValueを10ずつ増やしています。
- 非同期処理の中でコントロールを操作できないため,Current.Dispatcher.Invokeで,UIスレッドに戻してから,プログレスバーの値を変更しています。
パターン2:プログレスバーとテキストを重ねて表示する
この表示の仕方も結構ニーズがあると思います。ProgressBar自体にこの方法を実現するプロパティは実装されていないので,自分で実装する必要があります。やり方はProgressBarとTextBlockを同一のGrid上に配置し,同一の列と行の設定にします。同一のGridにこの2つしかコントロールがない場合はどちらも行列がゼロになっているので,あえて行列の設定をする必要はありません。
<StackPanel Margin="5,10,5,5" Orientation="Horizontal"> <Grid> <ProgressBar x:Name="BProgressBar" Margin="25,0,0,0" Height="30" Width="180" Minimum="0" Maximum="100" HorizontalAlignment="Left" ValueChanged="BProgressBar_ValueChanged" /> <TextBlock x:Name="BTextBlock" Margin="10,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" Text="xxx" Width="50" FontSize="20"/> </Grid> <Button x:Name="BButton" Margin="10,0,0,0" Click="BButton_Click" Height="30" Width="60" Content="Run"/> </StackPanel>
パターン1とほとんど同じです。違いはProgressBarとTextBlockを同一のGrid上に載せているだけです。
public MainWindow() { InitializeComponent(); BTextBlock.Text = BProgressBar.Value.ToString() + "%"; } private void BProgressBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { BTextBlock.Text = BProgressBar.Value.ToString() + "%"; } private void BButton_Click(object sender, RoutedEventArgs e) { Task.Run(() => { for (int i = 0; i < 10; i++) { System.Threading.Thread.Sleep(500); Application.Current.Dispatcher.Invoke(() => { BProgressBar.Value += 10; }); } }); }
パターン3:終了するタイミングが不明な時
すべての処理が,終了するタイミングがわかるわけではありません。データベースの問い合わせなどは,データベースからの返答がいつになるかわかりません。そういった場合は,処理中であることだけを示し,画面が固まっていないことを表現するためにも,何かしらのアニメーションが動作しているほうが望ましいです。そういった場合にプログレスバーの目盛りが,左から右に永遠と流れるだけの機能が実装されています。やり方はIsIndeterminate
というプロパティをTrueにするだけです。処理が終わったらFalseにすれば止まります。パターン2のTextBlockを重ねる方法を利用して「検索しています…」等と表示すれば,一層の効果があります。
<StackPanel Margin="5,10,5,5" Orientation="Horizontal"> <Grid> <ProgressBar x:Name="CProgressBar" Margin="25,0,0,0" Height="30" Width="180" Minimum="0" Maximum="100" HorizontalAlignment="Left" /> <TextBlock x:Name="CTextBlock" Margin="10,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" Text="" FontSize="14"/> </Grid> <Button x:Name="CButton" Margin="10,0,0,0" Click="CButton_Click" Height="30" Width="60" Content="Run"/> </StackPanel>
private void CButton_Click(object sender, RoutedEventArgs e) { CProgressBar.IsIndeterminate = true; CTextBlock.Text = "検索しています..."; }
処理を実行したタイミングでIsIndeterminateをTrueにして,TextBlockに検索中の文言を表示しています。処理が終わったタイミングでIsIndeterminateをFalseにしたり,TextBlockの文言を消す必要があります。
サンプルコード全体
<Window x:Class="WPF019.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WPF019" mc:Ignorable="d" Title="MainWindow" Height="170" Width="370"> <Grid> <StackPanel> <StackPanel Margin="5,10,5,5" Orientation="Horizontal"> <ProgressBar x:Name="AProgressBar" Margin="25,0,0,0" Height="30" Width="180" Minimum="0" Maximum="100" HorizontalAlignment="Left" ValueChanged="AProgressBar_ValueChanged" /> <TextBlock x:Name="ATextBlock" Margin="10,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" Text="xxx" Width="50" FontSize="20"/> <Button x:Name="AButton" Margin="10,0,0,0" Click="AButton_Click" Height="30" Width="60" Content="Run"/> </StackPanel> <StackPanel Margin="5,10,5,5" Orientation="Horizontal"> <Grid> <ProgressBar x:Name="BProgressBar" Margin="25,0,0,0" Height="30" Width="180" Minimum="0" Maximum="100" HorizontalAlignment="Left" ValueChanged="BProgressBar_ValueChanged" /> <TextBlock x:Name="BTextBlock" Margin="10,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" Text="xxx" Width="50" FontSize="20"/> </Grid> <Button x:Name="BButton" Margin="10,0,0,0" Click="BButton_Click" Height="30" Width="60" Content="Run"/> </StackPanel> <StackPanel Margin="5,10,5,5" Orientation="Horizontal"> <Grid> <ProgressBar x:Name="CProgressBar" Margin="25,0,0,0" Height="30" Width="180" Minimum="0" Maximum="100" HorizontalAlignment="Left" /> <TextBlock x:Name="CTextBlock" Margin="10,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" Text="" FontSize="14"/> </Grid> <Button x:Name="CButton" Margin="10,0,0,0" Click="CButton_Click" Height="30" Width="60" Content="Run"/> </StackPanel> </StackPanel> </Grid> </Window>
using System.Threading.Tasks; using System.Windows; namespace WPF019 { /// /// MainWindow.xaml の相互作用ロジック /// public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); ATextBlock.Text = AProgressBar.Value.ToString() + "%"; BTextBlock.Text = BProgressBar.Value.ToString() + "%"; } private void AProgressBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { ATextBlock.Text = AProgressBar.Value.ToString() + "%"; } private void AButton_Click(object sender, RoutedEventArgs e) { Task.Run(() => { for (int i = 0; i < 10; i++) { System.Threading.Thread.Sleep(500); Application.Current.Dispatcher.Invoke(() => { AProgressBar.Value += 10; }); } }); } private void BProgressBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { BTextBlock.Text = BProgressBar.Value.ToString() + "%"; } private void BButton_Click(object sender, RoutedEventArgs e) { Task.Run(() => { for (int i = 0; i < 10; i++) { System.Threading.Thread.Sleep(500); Application.Current.Dispatcher.Invoke(() => { BProgressBar.Value += 10; }); } }); } private void CButton_Click(object sender, RoutedEventArgs e) { CProgressBar.IsIndeterminate = true; CTextBlock.Text = "検索しています..."; } } }
- C#WPFの道#1!WPFのプロジェクト作成方法をわかりやすく解説!
- C#WPFの道#2!StackPanelの使い方をわかりやすく解説!
- C#WPFの道#3!Gridの使い方をわかりやすく解説!
- C#WPFの道#4!コントロールの名前の付け方をわかりやすく解説!
- C#WPFの道#5!イベントの定義の仕方をわかりやすく解説!
- C#WPFの道#6!リソースとStaticResourceの定義と使い方をわかりやすく解説!
- C#WPFの道#7!コントロールのスタイル定義のやり方をわかりやすく解説!
- C#WPFの道#8!グループごとのスタイル定義とBasedOnでの継承のやり方!
- C#WPFの道#9!SQLiteの使い方をわかりやすく解説!
- C#WPFの道#10!ListViewの使い方をわかりやすく解説!
- C#WPFの道#11!ListViewのフィルタリングの方法を解説!
- C#WPFの道#12!SQLiteとListViewでマスタ設定画面の作成!
- C#WPFの道#13!Buttonに画像と文字を並べる方法とRepeatButtonとToggleButton
- C#WPFの道#14!CheckBoxとIsThreeState、Indeterminateの使い方
- C#WPFの道#15!RadioButtonの書き方と使い方を解説
- C#WPFの道#16!Expanderの書き方と使い方を解りやすく解説
- C#WPFの道#17!GroupBoxの書き方と使い方を解りやすく解説
- C#WPFの道#18!Slider(スライダー)の書き方と使い方を解りやすく解説
- C#WPFの道#19!ProgressBarの書き方と使い方を解りやすく解説
- C#WPFの道#20!ComboBoxの書き方と使い方を解りやすく解説
- C#WPFの道#21!ListBoxの書き方と使い方を解りやすく解説
- C#WPFの道#22!TabControlの書き方と使い方を解りやすく解説
- C#WPFの道#23!TreeViewの書き方と使い方を解りやすく解説
- C#WPFの道#24!TextBlock,TextBoxの改行と文字の加工を解説
- C#WPFの道#25!Menuの書き方と使い方をわかりやすく解説!
- C#WPFの道#26!ToolBarの書き方と使い方をわかりやすく解説!
- C#WPFの道#27!StatusBarの書き方と使い方をわかりやすく解説!
- C#WPFの道#28!WrapPanelの書き方と使い方をわかりやすく解説!
- C#WPFの道#29!DockPanelの書き方と使い方をわかりやすく解説!
- C#WPFの道#30!Canvasの書き方と使い方をわかりやすく解説!