一.前言
申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等。
本文主要内容:
- ProcessBar自定义标准样式;
- ProcessBar自定义环形进度样式;
二.ProcessBar标准样式
效果图:
ProcessBar的样式非常简单:
<!--ProgressBar Style--> <Style TargetType="ProgressBar" x:Key="SimpleProgressBar"> <Setter Property="Background" Value="{StaticResource ControlBorderBrush}" /> <Setter Property="Maximum" Value="1" /> <Setter Property="Value" Value="0" /> <Setter Property="Height" Value="10" /> <Setter Property="IsTabStop" Value="False" /> <Setter Property="Foreground" Value="{StaticResource FocusBorderBrush}" /> <Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="local:ControlAttachProperty.CornerRadius" Value="0" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ProgressBar"> <Grid x:Name="Root" > <Border x:Name="PART_Track" Background="{TemplateBinding Background}" CornerRadius="{TemplateBinding local:ControlAttachProperty.CornerRadius}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> <Border x:Name="PART_Indicator" HorizontalAlignment="Left" Background="{TemplateBinding Foreground}" CornerRadius="{TemplateBinding local:ControlAttachProperty.CornerRadius}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> </Grid> <ControlTemplate.Triggers> <Trigger Property="Orientation" Value="Vertical"> <Setter Property="LayoutTransform" TargetName="Root" > <Setter.Value> <RotateTransform Angle="-90" /> </Setter.Value> </Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
使用示例:
<ProgressBar Margin="5" Value="{Binding Percent,Mode=OneWay}" Style="{StaticResource SimpleProgressBar}" x:Name="pro4"></ProgressBar> <ProgressBar Margin="5" Value="{Binding Percent,Mode=OneWay}" Height="15" x:Name="pro5" Background="LightSteelBlue" Foreground="OrangeRed" Style="{StaticResource SimpleProgressBar}"></ProgressBar>
三.ProcessBar环形进度样式
效果图:
样式定义也比较简单:
<!--注意:该样式的ProgressBar的最大值为1,,BorderThickness控制环的大小--> <!--ed需要引用:xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"--> <Style x:Key="LoopProcessBar" TargetType="{x:Type ProgressBar}"> <Setter Property="Background" Value="#C1D1DE"/> <Setter Property="Margin" Value="5"/> <Setter Property="Width" Value="300"/> <Setter Property="Height" Value="300"/> <Setter Property="BorderBrush" Value="BlueViolet"/> <Setter Property="BorderThickness" Value="60"/> <Setter Property="Foreground" Value="{StaticResource TextForeground}"/> <Setter Property="Maximum" Value="1"/> <Setter Property="Minimum" Value="0"/> <Setter Property="Value" Value="0"/> <Setter Property="IsTabStop" Value="False"/> <Setter Property="IsHitTestVisible" Value="False"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ProgressBar}"> <Viewbox Stretch="Uniform" VerticalAlignment="Center" HorizontalAlignment="Center"> <Grid Margin="{TemplateBinding Margin}" SnapsToDevicePixels="True" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" > <!--背景环--> <ed:Arc Margin="{TemplateBinding Margin}" Opacity="0.6" ArcThickness="{Binding Path=BorderThickness,RelativeSource={RelativeSource TemplatedParent},Mode=OneWay,Converter={x:Static local:XConverter.ThicknessToDoubleConverter}}" StartAngle="0" Fill="{TemplateBinding Background}" EndAngle="360" Stretch="None" x:Name="arcOuter" /> <!--值-环--> <ed:Arc Margin="{TemplateBinding Margin}" x:Name="arcValue" ArcThickness="{Binding Path=BorderThickness,RelativeSource={RelativeSource TemplatedParent},Mode=OneWay,Converter={x:Static local:XConverter.ThicknessToDoubleConverter}}" StartAngle="0" Fill="{TemplateBinding BorderBrush}" Stretch="None" Panel.ZIndex="2" EndAngle="{TemplateBinding Value, Converter={x:Static local:XConverter.PercentToAngleConverter}}" > </ed:Arc> </Grid> </Viewbox> </ControlTemplate> </Setter.Value> </Setter> </Style>
上面样式中使用了两个转换器:
- ThicknessToDoubleConverter:使用ProcessBar本身的属性BorderThickness设置环形宽度,把BorderThickness转换为环Arc宽度所需要的值;
- PercentToAngleConverter:当前进度值转换为环Arc的角度值;
这个地方有个小技巧,把常用的转换器声明为静态变量,XAML中以"x:Static"方式静态使用,这样使用的时候就方便多了,不用xaml中单独定义了。当然这样做也有弊端,因为静态变量本身的特点所决定的,不可滥用。
/// <summary> /// 百分比转换为角度值 /// </summary> public class PercentToAngleConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var percent = value.ToSafeString().ToDouble(); if (percent >= 1) return 360.0D; return percent * 360; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } /// <summary> /// 获取Thickness固定值double /// </summary> public class ThicknessToDoubleConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var thickness = (Thickness)value; return thickness.Left; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return DependencyProperty.UnsetValue; } }
使用示例:
<ProgressBar Style="{StaticResource LoopProcessBar}" Value="{Binding Percent,Mode=OneWay}" x:Name="pro1" ></ProgressBar> <Grid Width="200" Height="200"> <ProgressBar Style="{StaticResource LoopProcessBar}" Value="{Binding Percent,Mode=OneWay}" x:Name="pro2" Margin="0" Width="200" Height="200" BorderThickness="20" BorderBrush="#EF436F"/> <TextBlock FontSize="30" Text="{Binding Value,Mode=OneWay,ElementName=pro2,StringFormat={}{0:p1}}" VerticalAlignment="Center" HorizontalAlignment="Center"/> </Grid> <ProgressBar Style="{StaticResource LoopProcessBar}" x:Name="pro3" Value="{Binding Percent,Mode=OneWay}" Width="100" Height="100" BorderThickness="10" BorderBrush="#EFBF0E"></ProgressBar>