【WPF】ProgressRingを使って時間のかかる処理を分かりやすくする
おはようございます。
昨日に引き続き、Metro を使って画面変更を行います。
WEBなんかでよく見かける、処理中にローディング画像を表示するってのをやってみます。
重い処理なんかで、ローディング表示がない場合はユーザーが動いているのかどうか心配になり、挙句の果てに強制終了してしまったりしますので、大事ですよね。
体感速度も違ってきますし。
プログラムは前回のものを利用します。
スポンサーリンク
スタイルの追加
StyleDic.xaml
宣言の追加
1 2 3 4 | <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" xmlns:local="clr-namespace:WpfApp1.Style"> |
スタイルの追加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <!-- プログレスリング --> <Style x:Key="pgr-normal" TargetType="{x:TypeMah:ProgressRing}" > <Setter Property="Foreground"Value="#33adff"/> <Setter Property="IsActive"Value="False"/> <Setter Property="Width"Value="100"/> <Setter Property="Height"Value="100"/> <Setter Property="Panel.ZIndex"Value="100"/> </Style> <!-- プログレスオーバーレイ--> <Style x:Key="rec-overlay" TargetType="{x:TypeRectangle}" > <Setter Property="Fill"Value="#000000"/> <Setter Property="Opacity"Value="0.2"/> <Setter Property="Panel.ZIndex"Value="1000"/> <Setter Property="Margin"Value="0,0,0,30"/> <Setter Property="Visibility"Value="Collapsed"/> </Style> |
画面の修正
MainWindow.xaml
抜粋
1 2 3 4 5 6 | <!-- Gridの高さと幅を設定 --> <Grid Height="350"Width="530"> <!-- プログレスリングとオーバーレイを追加 --> <Rectangle x:Name="rec_overlay"Width="530"Height="330"Style="{StaticResource rec-overlay}" /> <Mah:ProgressRing x:Name="loading_image"Style="{StaticResource pgr-normal}"/> |
全体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | <Mah:MetroWindow x:Class="WpfApp1.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:WpfApp1" xmlns:Mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" mc:Ignorable="d" Title="一覧"Height="350"Width="530" GlowBrush="{DynamicResource AccentColorBrush}" BorderThickness="1" > <Window.Resources> <ResourceDictionary Source="/Style/StyleDic.xaml"/> </Window.Resources> <Grid Height="350"Width="530"> <Grid.Resources> <local:KindConverter x:Key="KindConv"/> </Grid.Resources> <Rectangle x:Name="rec_overlay"Width="530"Height="330"Style="{StaticResource rec-overlay}" /> <Mah:ProgressRing x:Name="loading_image"Style="{StaticResource pgr-normal}"/> <Label Content="名前:"Margin="10,10,0,0"Style="{StaticResource lb-normal}"/> <TextBox x:Name="search_name"Margin="56,12,0,0"HorizontalAlignment="Left"VerticalAlignment="Top"Width="120" Style="{StaticResource MetroTextBox}"/> <Label Content="種別:"Margin="201,10,0,0"Style="{StaticResource lb-normal}"/> <ComboBox x:Name="search_kind"Margin="252,12,0,0"HorizontalAlignment="Left"VerticalAlignment="Top"Width="125" Style="{StaticResource MetroComboBox}"/> <Button x:Name="search_button"Content="検索"HorizontalAlignment="Left"Margin="432,12,0,0"VerticalAlignment="Top"Width="75" Click="search_button_Click"Style="{DynamicResource SquareButtonStyle}"/> <DataGrid Name="dataGrid"HorizontalAlignment="Left"Margin="10,43,0,0"Width="497"Height="225"Style="{StaticResource grid-normal}" > <DataGrid.Columns> <DataGridTextColumn Binding="{Binding No}"ClipboardContentBinding="{x:Null}"Header="No"IsReadOnly="True"Width="50"/> <DataGridTextColumn Binding="{Binding Name}"ClipboardContentBinding="{x:Null}"Header="名前"IsReadOnly="True"Width="100"/> <DataGridTextColumn Binding="{Binding Sex}"ClipboardContentBinding="{x:Null}"Header="性別"IsReadOnly="True"Width="40"/> <DataGridTextColumn Binding="{Binding Age}"ClipboardContentBinding="{x:Null}"Header="年齢"IsReadOnly="True"Width="40"/> <DataGridTextColumn Binding="{Binding Kind, Converter={StaticResource KindConv}}"ClipboardContentBinding="{x:Null}"Header="種別"IsReadOnly="True"Width="120"/> <DataGridTextColumn Binding="{Binding Favorite}"ClipboardContentBinding="{x:Null}"Header="好物"IsReadOnly="True"Width="*"/> </DataGrid.Columns> </DataGrid> <Button x:Name="add_button"Content="追加"HorizontalAlignment="Left"Margin="10,273,0,0"VerticalAlignment="Top"Width="75"Height="30"Click="add_button_Click"Style="{DynamicResource AccentedSquareButtonStyle}"/> <Button x:Name="upd_button"Content="更新"HorizontalAlignment="Left"Margin="90,273,0,0"VerticalAlignment="Top"Width="75"Height="30"Click="upd_button_Click"Style="{DynamicResource AccentedSquareButtonStyle}"/> <Button x:Name="del_button"Content="削除"HorizontalAlignment="Left"Margin="170,273,0,0"VerticalAlignment="Top"Width="75"Height="30"Click="del_button_Click"Style="{DynamicResource AccentedSquareButtonStyle}"/> <Button x:Name="imp_button"Content="CSV読込"HorizontalAlignment="Left"Margin="250,273,0,0"VerticalAlignment="Top"Width="75"Height="30"Click="imp_button_Click"Style="{DynamicResource AccentedSquareButtonStyle}"/> <Button x:Name="exp_button"Content="CSV出力"HorizontalAlignment="Left"Margin="330,273,0,0"VerticalAlignment="Top"Width="75"Height="30"Click="exp_button_Click"Style="{DynamicResource AccentedSquareButtonStyle}"/> <Button x:Name="fld_button"Content="フォルダ参照"HorizontalAlignment="Left"Margin="410,273,0,0"VerticalAlignment="Top"Width="97"Height="30"Click="fld_button_Click"Style="{DynamicResource AccentedSquareButtonStyle}"/> </Grid> </Mah:MetroWindow> |
プログラムの修正
ライブラリ使用宣言の追加
MainWindow.xaml.cs
抜粋
1 | usingSystem.ComponentModel; |
検索処理の修正
検索処理を、BackgroundWorkerを使って非同期処理として分離します。
MainWindow.xaml.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | /// <summary> /// 検索処理(非同期) /// </summary> /// <param name="sender"></param> /// <param name="e"></param> privatevoidSearchProcess(objectsender,DoWorkEventArgse) { // 時間のかかるようにする System.Threading.Thread.Sleep(3000); using(varconn=newMySqlConnection("Database=DB01;Data Source=localhost;User Id=USER01;Password=USER01; sqlservermode=True;")) { conn.Open(); // 猫データマスタを取得してコンボボックスに設定する using(DataContext con=newDataContext(conn)) { StringsearchName=(e.Argument asObject[])[0]asString; StringsearchKind=(e.Argument asObject[])[1]asString; // データを取得 Table<Cat>tblCat=con.GetTable<Cat>(); // サンプルなので適当に組み立てる IQueryable<Cat>result; if(searchKind=="") { // 名前は前方一致のため常に条件していしても問題なし result=fromxintblCat wherex.Name.StartsWith(searchName) orderbyx.No selectx; } else { result=fromxintblCat wherex.Name.StartsWith(searchName)& x.Kind == searchKind orderby x.No select x; } e.Result=result.ToList(); } conn.Close(); } } /// <summary> /// 検索完了処理(非同期) /// </summary> /// <param name="sender"></param> /// <param name="e"></param> privatevoidSearchProcessCompleted(objectsender,RunWorkerCompletedEventArgse) { this.dataGrid.ItemsSource=e.Result asList<Cat>; ToggleProgressRing(); } /// <summary> /// 処理中イメージの表示/非表示切り替え /// /// </summary> privatevoidToggleProgressRing() { if(this.loading_image.IsActive) { this.loading_image.IsActive=false; this.rec_overlay.Visibility=Visibility.Collapsed; } else { this.loading_image.IsActive=true; this.rec_overlay.Visibility=Visibility.Visible; } } |
メソッドの修正
検索ボタンをクリックした際に、先ほど追加した非同期処理を呼び出すように修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | /// <summary> /// 検索ボタンクリックイベント. /// /// </summary> /// <param name="sender"></param> /// <param name="e"></param> privatevoidsearch_button_Click(objectsender,RoutedEventArgse) { logger.Info("検索ボタンクリック"); Object[]param=newObject[2]; param[0]=this.search_name.Text; param[1]=(this.search_kind.SelectedValue asKind).KindCd; BackgroundWorker worker=newBackgroundWorker(); worker.DoWork+=SearchProcess; worker.RunWorkerCompleted+=newRunWorkerCompletedEventHandler(SearchProcessCompleted); worker.RunWorkerAsync(param); ToggleProgressRing(); } |
起動してみる
いい感じですね。
ローディング表示だけだと、処理中にボタンなんかが押せてしまうので図形をかぶせるようにしてみました。
まとめ
簡単な(画面の少ない)アプリであればこんな方法でも十分かなと思います。
ソースはこちら
ではでは。
ディスカッション
コメント一覧
まだ、コメントがありません