정보
요청한 주제가 아래에 표시됩니다. 그러나 이 주제는 이 라이브러리에 포함되지 않습니다.

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 샘플은 다음과 같은 두 가지 문제를 해결하기 위해 작성되었습니다.

  • 성능 향상을 위해 작성자 스레드에서 실행되는 비활성화 상태 진행률 표시줄의 필요성

  • 방향 변경의 결과인 크기 조정을 처리할 수 있는 진행률 표시줄의 필요성

솔루션은 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. ".1"로 끝나는 모든 double 애니메이션 키 프레임 값은 ".1"이 제거되고 컨트롤의 너비의 백분율로 업데이트됩니다. 예를 들어 Value="33.1"은 33%의 백분율에 사용됩니다. 방향이 변경되고 컨트롤의 새 너비가 480인 경우 이 키 프레임 값은 약 160으로 변경됩니다.

  3. ".2"로 끝나는 모든 double 애니메이션 키 프레임 값은 ".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;
    }
    
    

표시: