酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

Windows PhoneでPopUpを使ってダウンロード中や激重処理中にユーザーに待ってもらう為のプログレスインジゲータバーを表示する

Windows Phone Advent Calendar "ひとり" 2011」第24日目です。 (遅延実行中です)

プログレスインジゲータをシステムトレイ上に表示する方法は「システムトレイ上にプログレスインジゲータバーを表示する」をご覧ください。

ウェブ上からデータを取得中や何らかの時間のかかる処理中にインジゲータを表示して、ユーザーに可能な限りストレスを与えないように工夫されているかと思います。

インジゲータを表示する方法はいくつかありますが、データ更新中などユーザー操作を抑止しなければいけないシーンは当然あるかと思います。そんな時よく使われる方法としては、ユーザーが操作可能なアプリ領域を、大きなサイズのGridやらUserControlで覆い隠してやることです。

f:id:ch3cooh393:20141225174628p:plain

今回は、「Wainting...」と表示されたユーザーコントロールを作成して、処理をおこなっているMainPage上に被せてしまいましょう。しかし、フレームとページの構成に影響されずに一番前にウェイトコントロールを表示させるためにはどうすれば良いでしょうか。

Windows Phoneの画面構成要素について

Windows Phoneの画面構成についておさらいしましょう。

PhoneApplicationFrame(フレーム)はビジュアルツリーの最上位にひとつだけ存在しており、PhoneApplicationPage(ページ)はナビゲーションの単位で基本的に画面遷移の数だけフレームの子要素としてページが複数個存在しています。

PopUp(ポップアップ)は、フレームとページと同じくウィンドウを管理する要素ですが、ビジュアルツリーの最上位に表示されます。つまりフレームよりも前に表示されるのが特徴です。

f:id:ch3cooh393:20141225174656p:plain

インジゲータバー付きのユーザーコントロールを作成する

それではポップアップの子要素として表示するユーザーコントロールを作成します。

ソリューションエクスプローラーからプロジェクトを選択して、コンテキストメニューから[追加]→[新しい項目の追加]を選択します。新しい項目の追加ダイアログが表示されるので「Windows Phone ユーザーコントロール」を選択します。名前は「WaitingControl」にします。

<UserControl
    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:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit" 
	x:Class="ProgressIndicatorTest2.WaitingControl"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="768" d:DesignWidth="480">

    <Grid x:Name="LayoutRoot" Width="480" Height="800">
        <Rectangle Fill="{StaticResource PhoneBackgroundBrush}" Opacity="0.7"/>
    	<TextBlock HorizontalAlignment="Center" TextWrapping="Wrap" Text="waiting..." 
		VerticalAlignment="Center" Foreground="{StaticResource PhoneForegroundBrush}" Margin="0,30,0,0" FontFamily="Segoe WP Semibold"/>
    	<toolkit:PerformanceProgressBar VerticalAlignment="Center" IsIndeterminate="True"/>
    </Grid>
</UserControl>

プログラム側は生成時そのままで問題ありません。

using System.Windows.Controls;

namespace ProgressIndicatorTest2 {
    public partial class WaitingControl : UserControl {
        public WaitingControl() {
            InitializeComponent();
        }
    }
}

ページ側でのWaitingControlの使い方

時間の掛かる処理の代替処理としてReactive Extensionsで5秒間のタイマーを実行します。ボタンが押下された時点でポップアップとしてWaitingControlを表示させてページに被せます。2秒のタイマーが満了するとポップアップを閉じています。

using System;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Reactive;
using System.Windows.Controls.Primitives;

namespace ProgressIndicatorTest2 {
    public partial class MainPage : PhoneApplicationPage {

        private Popup popup = null;

        // コンストラクター
        public MainPage() {
            InitializeComponent();

            popup = new Popup();
            popup.Child = new WaitingControl();
        }

        private void button1_Click(object sender, RoutedEventArgs e) {

            // ポップアップを表示する
            popup.IsOpen = true;

            // 何らかの時間の掛かる処理が5秒間実行されるとする(仮定)
            Observable.Timer(TimeSpan.FromSeconds(5))
                .ObserveOnDispatcher()
                .Subscribe(_ => {

                    // 処理が完了した!ポップアップを非表示にする
                    popup.IsOpen = false;
                });
        }
    }
}

関連記事

blog.ch3cooh.jp