방법: 사용자 지정 미정 진행률 표시줄 만들기

2012-02-09

ProgressBar 클래스를 사용하여 응용프로그램에 진행률 표시줄을 추가할 수 있습니다. 단, 미정 진행률 표시줄을 추가하려는 경우에는 ProgressBar를 사용하면 응용프로그램의 성능이 저하될 수 있습니다. 이것은 현재 ProgressBar의 구현이 합성자 스레드가 아니라 UI 스레드에서 미정 진행률 표시줄을 실행하기 때문입니다.

대신 성능 향상을 위해, CustomIndeterminateProgressBar 샘플을 사용하여 합성자 스레드에서 실행되는 미정 진행률 표시줄을 추가할 수 있습니다. 이 항목에서는 샘플이 작동하는 방식과 이 샘플을 사용하여 응용프로그램에 미정 진행률 표시줄을 추가하는 방법에 대해 설명합니다.

이 섹션에서는 샘플이 작동하는 방식에 대해 설명하지만, 샘플을 사용하기 위해 이 섹션을 읽어볼 필요는 없습니다. 샘플을 있는 그대로 사용하려면 다음 섹션으로 건너뛰고 지침을 따르십시오.

CustomIndeterminateProgressBar 샘플은 다음과 같은 두 가지 문제를 해결하기 위해 작성되었습니다.

  • 성능 향상을 위해 합성자 스레드에서 실행되는 미정 진행률 표시줄의 필요성

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

솔루션은 XAML 코드와 추가 .cs 파일 둘 다에서 구현됩니다.

XAML 코드의 경우

  1. CustomIndeterminateProgressBar의 App.xaml에서 스타일은 Indeterminate 상태에 대한 사용자 지정 VisualState를 포함합니다. DoubleAnimationUsingKeyFrames 개체는 미정 진행률 표시줄에 애니메이션 효과를 적용하는 데 사용됩니다.

  2. 각 키 프레임의 은 ".1" 또는 ".2"로 끝나는 숫자이며, 값을 식별하기 위한 명명 규칙의 한 종류로 사용됩니다. 페이지 방향이 변경되면 사용자 지정 프로세서는 이 접미사를 가진 값을 찾아 각각 컨트롤 너비 또는 높이의 비율로 변환합니다.

  3. CustomIndeterminateProgressBar는 MainPage.xaml에서 인스턴스화됩니다. 이 샘플에서 버튼은 진행률 표시줄의 표시 여부를 제어하고 Visibility 및 IsIndeterminate 플래그를 토글합니다. 성능 향상을 위해서는 응용프로그램을 작성할 때 진행률 표시줄이 화면에 표시되지 않는 동안은 진행률 표시줄이 보이지도 않고 실행되지도 않도록 해야 합니다.

코드 숨김 파일의 경우

RelativeAnimatingContentControl.cs 파일은 방향 변경이 발생할 경우 미정 진행률 표시줄 크기를 조정하는 로직을 포함합니다. 방향 변경 시 다음 단계가 수행됩니다.

  1. Storyboard를 포함하는 VisualState의 경우 DoubleAnimation 또는 DoubleAnimationUsingKeyFrames 값이 두 개의 처리 메서드 중 하나로 보내집니다.

  2. "1"로 끝나는 이중 애니메이션 키 프레임 값은 "1"이 제거되고 컨트롤의 너비에 해당하는 비율로 업데이트됩니다. 예를 들어 Value="33.1"은 33% 비율로 사용됩니다. 그러므로 방향이 변경되어 컨트롤의 새 너비가 480이면 이 키 프레임 값은 약 160으로 변경됩니다.

  3. "2"로 끝나는 이중 애니메이션 키 프레임 값은 "2"가 제거되고 컨트롤의 높이에 해당하는 비율로 업데이트됩니다.

샘플을 가져오고 프로젝트를 만들려면

  1. Windows Phone용 코드 샘플에서 CustomIndeterminateProgressBar 샘플을 다운로드합니다.

  2. Visual Studio에서 새 Windows Phone 응용프로그램 프로젝트를 만듭니다.

  3. 솔루션 탐색기에서 프로젝트 이름을 마우스 오른쪽 버튼으로 클릭한 다음 추가, 기존 항목을 사용하여 샘플에서 루트 디렉터리로 RelativeAnimatingContentControl.cs 파일을 추가합니다.

CustomIndeterminateProgressBar 스타일을 추가하려면

  1. App.xaml 파일을 엽니다. <Application> 태그 내에, 나머지 네임스페이스 선언이 있는 다음 XMLNS 선언을 추가합니다.

    xmlns:unsupported="clr-namespace:Microsoft.Phone.Controls.Unsupported"
    
  2. 다음 XAML 코드를 <Application.Resources> 태그 내에 추가합니다.

    <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;
    }
    
    

표시: