ProgressbarStyle.xaml

99 lines | 6.75 kB Blame History Raw Download
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:PasswordApp.WPF.Style"
                    xmlns:converters="clr-namespace:WPF.Common.WPF.Converters">
    <Style x:Key="RoundProgressBarStyle" TargetType="{x:Type ProgressBar}"
       xmlns:sys="clr-namespace:System;assembly=mscorlib">
        <Style.Resources>
            <converters:RoundProgressPathConverter x:Key="RoundProgressPathConverter"/>
            <!-- нам понадобится пара констант -->
            <!-- доля рабиуса для внутренней части -->
            <sys:Double x:Key="RelativeThickness">0.75</sys:Double>
            <!-- просто 0 -->
            <sys:Double x:Key="Zero">0.0</sys:Double>
            <!-- просто 1 -->
            <sys:Double x:Key="One">1.0</sys:Double>
            <!-- какой процент рисовать для неопределённого состояния -->
            <sys:Double x:Key="IndeterminatePart">0.25</sys:Double>
            <!-- обычно прогресс по умолчанию зелёный -->
            <SolidColorBrush x:Key="ProgressBar.Progress" Color="#FF06B025"/>
            <!-- стандартный фон -->
            <SolidColorBrush x:Key="ProgressBar.Background" Color="#FFE6E6E6"/>
            <!-- стандартный цвет границы -->
            <SolidColorBrush x:Key="ProgressBar.Border" Color="#FFBCBCBC"/>
        </Style.Resources>
        <Setter Property="Foreground" Value="{StaticResource ProgressBar.Progress}"/>
        <Setter Property="Background" Value="{StaticResource ProgressBar.Background}"/>
        <Setter Property="BorderBrush" Value="{StaticResource ProgressBar.Border}"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ProgressBar}">
                    <Grid x:Name="TemplateRoot">
                        <!-- в неопределённом состоянии запускаем вращающуюся анимацию -->
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Determinate"/>
                                <VisualState x:Name="Indeterminate">
                                    <Storyboard RepeatBehavior="Forever">
                                        <DoubleAnimation 
                                        Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"
                                        Storyboard.TargetName="Animation"
                                        From="0" To="360" Duration="0:0:2"/>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>

                        <!-- это фон, красим его в цвет фона-->
                        <Path Fill="{TemplateBinding Background}" Stretch="Uniform"
                          Stroke="{TemplateBinding BorderBrush}" StrokeThickness="{TemplateBinding BorderThickness}">
                            <Path.Data>
                                <MultiBinding Converter="{StaticResource RoundProgressPathConverter}"
                                          ConverterParameter="{StaticResource RelativeThickness}">
                                    <!-- val=1, min=0, max=1 даёт полный круг -->
                                    <Binding Source="{StaticResource One}"/>
                                    <Binding Source="{StaticResource Zero}"/>
                                    <Binding Source="{StaticResource One}"/>
                                </MultiBinding>
                            </Path.Data>
                        </Path>
                        <Path Fill="{TemplateBinding Foreground}" Stretch="Uniform" Name="Indicator">
                            <Path.Data>
                                <MultiBinding Converter="{StaticResource RoundProgressPathConverter}"
                                          ConverterParameter="{StaticResource RelativeThickness}">
                                    <Binding Path="Value" RelativeSource="{RelativeSource TemplatedParent}"/>
                                    <Binding Path="Minimum" RelativeSource="{RelativeSource TemplatedParent}"/>
                                    <Binding Path="Maximum" RelativeSource="{RelativeSource TemplatedParent}"/>
                                </MultiBinding>
                            </Path.Data>
                        </Path>
                        <!-- это анимировнная штука, будет показываться в неопределённом состоянии -->
                        <Path Fill="{TemplateBinding Foreground}" Stretch="Uniform" Name="Animation"
                          Visibility="Collapsed" RenderTransformOrigin="0.5,0.5">
                            <Path.Data>
                                <MultiBinding Converter="{StaticResource RoundProgressPathConverter}"
                                          ConverterParameter="{StaticResource RelativeThickness}">
                                    <Binding Source="{StaticResource IndeterminatePart}"/>
                                    <Binding Source="{StaticResource Zero}"/>
                                    <Binding Source="{StaticResource One}"/>
                                </MultiBinding>
                            </Path.Data>
                            <!-- положим пустое вращение, чтобы к нему цеплялась анимация -->
                            <Path.RenderTransform>
                                <RotateTransform/>
                            </Path.RenderTransform>
                        </Path>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <!-- в случае неопределённого состояния уберём нормальный индикатор и покажем анимацию -->
                        <Trigger Property="IsIndeterminate" Value="true">
                            <Setter Property="Visibility" TargetName="Indicator" Value="Collapsed"/>
                            <Setter Property="Visibility" TargetName="Animation" Value="Visible"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>