情報
要求されたトピックは次のとおりです。しかし、このトピックはこのライブラリには含まれていません。

Windows Phone 8 の不確定なカスタム プログレス バーを作成する方法

2014/06/18

対象: Windows Phone OS 7.1

 

アプリで時間のかかる処理を実行するときは、ProgressBar コントロールを使用して、進行状況を表示することをお勧めします。ただし、不確定なプログレス バーの追加を計画している場合、ProgressBar クラスの使用によって Windows Phone OS 7.1 アプリのパフォーマンスが低下する可能性があります。ProgressBar の Windows Phone OS 7.1 実装では、コンポジター スレッドではなく UI スレッドで不確定なプログレス バーが実行されるためです。

その代わりに、CustomIndeterminateProgressBar サンプルを使用して、コンポジター スレッドで実行される不確定なプログレス バーを追加し、パフォーマンスを向上させることができます。このトピックでは、このサンプルの動作原理と、このサンプルを使用して不確定なプログレス バーをアプリに追加する方法について説明します。

メモメモ:

Windows Phone 8 では、ProgressBar コントロールが更新され、不確定なプログレス バーとして使用する場合でも、以前と同じパフォーマンスの問題は発生しなくなりました。Windows Phone 8 を対象とするアプリを作成する場合は、ProgressBar を使用してください。

このトピックは、次のセクションで構成されています。

 

このセクションでは、サンプルのしくみについて説明しますが、サンプルを使用するだけでよい場合はこのセクションを読む必要はありません。サンプルを現状のまま使用する場合は、次のセクションに進んで指示に従ってください。

CustomIndeterminateProgressBar サンプルは、次の 2 つの問題を解決するために作成されました。

  • パフォーマンスを向上させるために、コンポジター スレッドで実行される不確定なカスタム プログレス バーが必要であること。

  • 向きの変更による拡大縮小を処理できるプログレス バーが必要であること。

このソリューションは XAML コードと、追加の .cs ファイルで実装されています。

XAML コードの場合

  1. CustomIndeterminateProgressBar に対応する App.xaml のスタイルには、Indeterminate 状態に相当するカスタムの VisualState が含まれています。DoubleAnimationUsingKeyFrames オブジェクトを使用して、不確定なプログレス バーをアニメーション化します。

  2. 各キー フレームの Value は、".1" または ".2" で終わる数値であり、この方式を名前付け規則のように使用して、値を識別します。ページの向きが変化した場合、カスタム プロセッサはこの接尾辞を持つ値を検索し、コントロールの幅または高さを基準とした比率に合わせてそれぞれの値を変換します。

  3. CustomIndeterminateProgressBar を MainPage.xaml 内でインスタンス化します。サンプルでは、ボタンを使用して、プログレス バーが表示されるかどうかを制御し、Visibility フラグと IsIndeterminateProperty フラグの両方を切り替えます。パフォーマンスを向上させるために、アプリの構築時にプログレス バーが画面に表示されていないときは、プログレス バーが描画および実行されないようにする必要があります。

分離コード ファイルの場合

RelativeAnimatingContentControl.cs ファイルには、向きの変化が発生したときに不確定なプログレス バーを拡大縮小するロジックが含まれています。向きが変化したときに、次の手順が実行されます。

  1. Storyboard を含む任意の VisualState で、DoubleAnimation または DoubleAnimationUsingKeyFrames の各値が 2 つの処理メソッドのいずれかに送信されます。

  2. ".1" で終わるダブル アニメーション キー フレーム値から ".1" を除去し、コントロールの幅を基準とする比率に更新します。たとえば、33% の比率を表すために、Value="33.1" という値を使用します。向きが変化し、コントロールの新しい幅が 480 の場合、このキー フレーム値は約 160 に変更されます。

  3. ".2" で終わるダブル アニメーション キー フレーム値から ".2" を除去し、コントロールの高さを基準とする比率に更新します。

サンプルを取得しプロジェクトを作成するには

  1. CustomIndeterminateProgressBar サンプルをダウンロードします。

  2. Visual Studio で、新しい Windows Phone アプリ  プロジェクトを作成します。

  3. ソリューション エクスプローラーで、プロジェクト名を右クリックし、[既存項目追加] を使用してサンプルからルート ディレクトリに RelativeAnimatingContentControl.cs ファイルを追加します。

CustomIndeterminateProgressBar スタイルを追加するには

  1. App.xaml ファイルを開きます。<Application> タグの中で、他の名前空間の宣言と共に、次の XMLNS 宣言を追加します。

    xmlns:unsupported="clr-namespace:Microsoft.Phone.Controls.Unsupported"
    
  2. <Application.Resources> タグの中で、次の XAML コードを追加します。

    <Style x:Key="CustomIndeterminateProgressBar" TargetType="ProgressBar"> 
        <Setter Property="Foreground" Value="{StaticResource PhoneAccentBrush}"/> 
        <Setter Property="Background" Value="{StaticResource PhoneAccentBrush}"/> 
        <Setter Property="Maximum" Value="100"/> 
        <Setter Property="IsHitTestVisible" Value="False"/> 
        <Setter Property="Padding" Value="{StaticResource PhoneHorizontalMargin}"/> 
        <Setter Property="Template"> 
            <Setter.Value> 
                <ControlTemplate TargetType="ProgressBar"> 
                    <unsupported:RelativeAnimatingContentControl HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"> 
                        <unsupported:RelativeAnimatingContentControl.Resources> 
                            <ExponentialEase EasingMode="EaseOut" Exponent="1" x:Key="ProgressBarEaseOut"/> 
                            <ExponentialEase EasingMode="EaseOut" Exponent="1" x:Key="ProgressBarEaseIn"/> 
                        </unsupported:RelativeAnimatingContentControl.Resources> 
                        <VisualStateManager.VisualStateGroups> 
                            <VisualStateGroup x:Name="CommonStates"> 
                                <VisualState x:Name="Determinate"/> 
                                <VisualState x:Name="Indeterminate"> 
                                    <Storyboard RepeatBehavior="Forever" Duration="00:00:04.4"> 
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="IndeterminateRoot"> 
                                            <DiscreteObjectKeyFrame KeyTime="0"> 
                                                <DiscreteObjectKeyFrame.Value> 
                                                    <Visibility>Visible</Visibility> 
                                                </DiscreteObjectKeyFrame.Value> 
                                            </DiscreteObjectKeyFrame> 
                                        </ObjectAnimationUsingKeyFrames> 
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="DeterminateRoot"> 
                                            <DiscreteObjectKeyFrame KeyTime="0"> 
                                                <DiscreteObjectKeyFrame.Value> 
                                                    <Visibility>Collapsed</Visibility> 
                                                </DiscreteObjectKeyFrame.Value> 
                                            </DiscreteObjectKeyFrame> 
                                        </ObjectAnimationUsingKeyFrames> 
                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.0" Storyboard.TargetProperty="X" Storyboard.TargetName="R1TT"> 
                                            <LinearDoubleKeyFrame KeyTime="00:00:00.0" Value="0.1"/> 
                                            <EasingDoubleKeyFrame KeyTime="00:00:00.5" Value="33.1" EasingFunction="{StaticResource ProgressBarEaseOut}"/> 
                                            <LinearDoubleKeyFrame KeyTime="00:00:02.0" Value="66.1"/> 
                                            <EasingDoubleKeyFrame KeyTime="00:00:02.5" Value="100.1" EasingFunction="{StaticResource ProgressBarEaseIn}"/> 
                                        </DoubleAnimationUsingKeyFrames> 
                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.2" Storyboard.TargetProperty="X" Storyboard.TargetName="R2TT"> 
                                            <LinearDoubleKeyFrame KeyTime="00:00:00.0" Value="0.1"/> 
                                            <EasingDoubleKeyFrame KeyTime="00:00:00.5" Value="33.1" EasingFunction="{StaticResource ProgressBarEaseOut}"/> 
                                            <LinearDoubleKeyFrame KeyTime="00:00:02.0" Value="66.1"/> 
                                            <EasingDoubleKeyFrame KeyTime="00:00:02.5" Value="100.1" EasingFunction="{StaticResource ProgressBarEaseIn}"/> 
                                        </DoubleAnimationUsingKeyFrames> 
                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.4" Storyboard.TargetProperty="X" Storyboard.TargetName="R3TT"> 
                                            <LinearDoubleKeyFrame KeyTime="00:00:00.0" Value="0.1"/> 
                                            <EasingDoubleKeyFrame KeyTime="00:00:00.5" Value="33.1" EasingFunction="{StaticResource ProgressBarEaseOut}"/> 
                                            <LinearDoubleKeyFrame KeyTime="00:00:02.0" Value="66.1"/> 
                                            <EasingDoubleKeyFrame KeyTime="00:00:02.5" Value="100.1" EasingFunction="{StaticResource ProgressBarEaseIn}"/> 
                                        </DoubleAnimationUsingKeyFrames> 
                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.6" Storyboard.TargetProperty="X" Storyboard.TargetName="R4TT"> 
                                            <LinearDoubleKeyFrame KeyTime="00:00:00.0" Value="0.1"/> 
                                            <EasingDoubleKeyFrame KeyTime="00:00:00.5" Value="33.1" EasingFunction="{StaticResource ProgressBarEaseOut}"/> 
                                            <LinearDoubleKeyFrame KeyTime="00:00:02.0" Value="66.1"/> 
                                            <EasingDoubleKeyFrame KeyTime="00:00:02.5" Value="100.1" EasingFunction="{StaticResource ProgressBarEaseIn}"/> 
                                        </DoubleAnimationUsingKeyFrames> 
                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.8" Storyboard.TargetProperty="X" Storyboard.TargetName="R5TT"> 
                                            <LinearDoubleKeyFrame KeyTime="00:00:00.0" Value="0.1"/> 
                                            <EasingDoubleKeyFrame KeyTime="00:00:00.5" Value="33.1" EasingFunction="{StaticResource ProgressBarEaseOut}"/> 
                                            <LinearDoubleKeyFrame KeyTime="00:00:02.0" Value="66.1"/> 
                                            <EasingDoubleKeyFrame KeyTime="00:00:02.5" Value="100.1" EasingFunction="{StaticResource ProgressBarEaseIn}"/> 
                                        </DoubleAnimationUsingKeyFrames> 
                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="R1"> 
                                            <DiscreteDoubleKeyFrame KeyTime="0" Value="1"/> 
                                            <DiscreteDoubleKeyFrame KeyTime="00:00:02.5" Value="0"/> 
                                        </DoubleAnimationUsingKeyFrames> 
                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.2" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="R2"> 
                                            <DiscreteDoubleKeyFrame KeyTime="0" Value="1"/> 
                                            <DiscreteDoubleKeyFrame KeyTime="00:00:02.5" Value="0"/> 
                                        </DoubleAnimationUsingKeyFrames> 
                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.4" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="R3"> 
                                            <DiscreteDoubleKeyFrame KeyTime="0" Value="1"/> 
                                            <DiscreteDoubleKeyFrame KeyTime="00:00:02.5" Value="0"/> 
                                        </DoubleAnimationUsingKeyFrames> 
                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.6" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="R4"> 
                                            <DiscreteDoubleKeyFrame KeyTime="0" Value="1"/> 
                                            <DiscreteDoubleKeyFrame KeyTime="00:00:02.5" Value="0"/> 
                                        </DoubleAnimationUsingKeyFrames> 
                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.8" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="R5"> 
                                            <DiscreteDoubleKeyFrame KeyTime="0" Value="1"/> 
                                            <DiscreteDoubleKeyFrame KeyTime="00:00:02.5" Value="0"/> 
                                        </DoubleAnimationUsingKeyFrames> 
                                    </Storyboard> 
                                </VisualState> 
                            </VisualStateGroup> 
                        </VisualStateManager.VisualStateGroups> 
                        <Grid> 
                            <Grid x:Name="DeterminateRoot" Margin="{TemplateBinding Padding}" Visibility="Visible"> 
                                <Rectangle x:Name="ProgressBarTrack" Fill="{TemplateBinding Background}" Height="4" Opacity="0.1"/> 
                                <Rectangle x:Name="ProgressBarIndicator" Fill="{TemplateBinding Foreground}" HorizontalAlignment="Left" Height="4"/> 
                            </Grid> 
                            <Border x:Name="IndeterminateRoot" Margin="{TemplateBinding Padding}" Visibility="Collapsed"> 
                                <Grid HorizontalAlignment="Left"> 
                                    <Rectangle Fill="{TemplateBinding Foreground}" Height="4" IsHitTestVisible="False" Width="4" x:Name="R1" Opacity="0" CacheMode="BitmapCache"> 
                                        <Rectangle.RenderTransform> 
                                            <TranslateTransform x:Name="R1TT"/> 
                                        </Rectangle.RenderTransform> 
                                    </Rectangle> 
                                    <Rectangle Fill="{TemplateBinding Foreground}" Height="4" IsHitTestVisible="False" Width="4" x:Name="R2" Opacity="0" CacheMode="BitmapCache"> 
                                        <Rectangle.RenderTransform> 
                                            <TranslateTransform x:Name="R2TT"/> 
                                        </Rectangle.RenderTransform> 
                                    </Rectangle> 
                                    <Rectangle Fill="{TemplateBinding Foreground}" Height="4" IsHitTestVisible="False" Width="4" x:Name="R3" Opacity="0" CacheMode="BitmapCache"> 
                                        <Rectangle.RenderTransform> 
                                            <TranslateTransform x:Name="R3TT"/> 
                                        </Rectangle.RenderTransform> 
                                    </Rectangle> 
                                    <Rectangle Fill="{TemplateBinding Foreground}" Height="4" IsHitTestVisible="False" Width="4" x:Name="R4" Opacity="0" CacheMode="BitmapCache"> 
                                        <Rectangle.RenderTransform> 
                                            <TranslateTransform x:Name="R4TT"/> 
                                        </Rectangle.RenderTransform> 
                                    </Rectangle> 
                                    <Rectangle Fill="{TemplateBinding Foreground}" Height="4" IsHitTestVisible="False" Width="4" x:Name="R5" Opacity="0" CacheMode="BitmapCache"> 
                                        <Rectangle.RenderTransform> 
                                            <TranslateTransform x:Name="R5TT"/> 
                                        </Rectangle.RenderTransform> 
                                    </Rectangle> 
                                </Grid> 
                            </Border> 
                        </Grid> 
                    </unsupported:RelativeAnimatingContentControl> 
                </ControlTemplate> 
            </Setter.Value> 
        </Setter> 
    </Style>
    

CustomInderminateProgressBar を追加するには

  1. 次のコードは IsIndeterminate フラグを true に設定するので、サンプルを実行するとプログレス バーがすぐに表示されます。XAML にプログレス バーを追加するには、次のコードを使用します。

    <ProgressBar 
       IsIndeterminate="true"
       x:Name="customIndeterminateProgressBar"
       Style="{StaticResource CustomIndeterminateProgressBar}"
    />
    

    MainPage.xaml のうち、ContentPanel という x:Name を持つ <Grid> タグの中に上記のコードを追加します。

  2. アプリでプログレス バーを使用する場合、プログレス バーが IsIndeterminate = false に設定されていて、プログレス バーが使用中でないときは Visibility プロパティが Collapsed に設定されていることを確認します。サンプルはデモンストレーションの目的で、クリック ハンドラー内でこれらの値を切り替えるボタンを設定することにより、この確認を行っています。値の設定や切り替えを実行したくない場合は、代わりに IsIndeterminate でデータ バインディングを使用するように設定できます。

    ボタンを使用して値を切り替えるこのサンプルの場合、MainPage.xaml で、前の手順で登場した ProgressBar コードのすぐ下に次のコードを追加します。

    <Button Content="Toggle ProgressBar" Height="72" HorizontalAlignment="Left" Margin="81,450,0,0" Name="toggleButton" VerticalAlignment="Top" Width="300" Click="toggleButton_Click" />
    
    

    クリック ハンドラーの中で次のコードを使用して値を切り替えます。

    customIndeterminateProgressBar.IsIndeterminate = !(customIndeterminateProgressBar.IsIndeterminate);
    
    if (customIndeterminateProgressBar.Visibility == Visibility.Collapsed)
    {
       customIndeterminateProgressBar.Visibility = Visibility.Visible;
    }
    else
    {
       customIndeterminateProgressBar.Visibility = Visibility.Collapsed;
    }
    
    

表示: