▪ 前言

项目开发需要,需要做一个圆形的进度条,但是发现 WPF 自带的进度条控件 ProgressBar 无法直接变成圆形,经过不停的Baidu、Google,终于找到了基于 ProgressBar 构建圆形进度条的方法

▪ 效果图

圆形progressbar进度条 wpf圆形进度条_Arc

▪ 辅助控件引用

在改造 ProgressBar 控件中,我们将用到 ControlTemplate 模板功能以及 <ed:Arc> 控件。<ed:Arc> 是一个画圆弧的控件(非 WPF 内置的控件),所以我们必须引用进来,否则使用将编译出错。

  1. .Net 框架的版本必须大于等于 4.0
  2. 在项目的 引用 中右键 -> 添加引用,在 程序集 -> 扩展 里面找到 Microsoft.Expression.Drawing 勾选引用
  3. 在窗体的 xaml 文件里的 标签添加如下代码:xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"

▪ 改变 ProgressBar 默认模板(基础)

在窗体 xaml 文件里加入如下代码:
<!-- 基于样式的 ControlTemplate 模板资源 -->
<Window.Resources>
    <Style x:Key="styleProgressBar" TargetType="{x:Type ProgressBar}">
        <Setter Property="Width" Value="100"/>
        <Setter Property="Height" Value="100"/>
        <Setter Property="Maximum" Value="360"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ProgressBar}">
                    <Grid Width="100" Height="100" HorizontalAlignment="Center" VerticalAlignment="Top">
                        <ed:Arc ArcThickness="5" StartAngle="0" Fill="{TemplateBinding Background}" Stretch="None" EndAngle="360"/>
                        <ed:Arc ArcThickness="5" StartAngle="0" Fill="{TemplateBinding Foreground}" Stretch="None" EndAngle="{TemplateBinding Value}"></ed:Arc>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

<ProgressBar Style="{StaticResource styleProgressBar}" Value="240" Foreground="#FF000000" Background="#FFFFFFFF"></ProgressBar>

圆形进度条的值应该是 0 ~ 360 度,所以我们在样式里直接限制 ProgressBar 最大值是 360,宽度和高度根据实际情况设置

以上代码仅仅是构建了圆形进度条,效果图 上标题、剩余时间、备注并没有

▪ 改变 ProgressBar 默认模板(高级)

ProgressBar 控件并没有标题、剩余时间、备注等属性字段,所以在样式的 ControlTemplate 中就不能直接使用 {TemplateBinding ...} 进行属性值的绑定。

所以此处我们将使用 ProgressBar 控件的 DataContext 属性进行数据绑定,在样式的 ControlTemplate 中我们就可以直接使用 {Binding ...} 调用数据。

在窗体 xaml 文件里加入如下代码:
<!-- 基于样式的 ControlTemplate 模板资源 -->
<Window.Resources>
    <Style x:Key="styleProgressBar" TargetType="{x:Type ProgressBar}">
        <Setter Property="Width" Value="100"/>
        <Setter Property="Height" Value="125"/>
        <Setter Property="Maximum" Value="360"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ProgressBar}">
                    <StackPanel Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" Margin="{TemplateBinding Margin}" SnapsToDevicePixels="True">
                        <Label Height="25" Foreground="#FFFFFFFF" Content="{Binding title}" HorizontalAlignment="Center" VerticalAlignment="Top"></Label>
                        <Grid Width="75" Height="75" HorizontalAlignment="Center" VerticalAlignment="Top">
                            <ed:Arc ArcThickness="5" StartAngle="0" Fill="{TemplateBinding Background}" Stretch="None" EndAngle="360"/>
                            <Label Content="{Binding progress}" Foreground="{TemplateBinding Foreground}" VerticalAlignment="Center" HorizontalAlignment="Center"></Label>
                            <ed:Arc ArcThickness="5" StartAngle="0" Fill="{TemplateBinding Foreground}" Stretch="None" EndAngle="{TemplateBinding Value}"></ed:Arc>
                        </Grid>
                        <Label Height="25" Foreground="#FFFFFFFF" Content="{Binding content}" HorizontalAlignment="Center" VerticalAlignment="Top"></Label>
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

<!-- ProgressBar 在窗体的 cs 文件中动态创建并追加到 uiProgressBars 中 -->
<WrapPanel x:Name="uiProgressBars"></WrapPanel>
在窗体 cs 文件里加入如下代码:
// 声明圆形进度条的数据对象
class ProgressData
{
    public string title { set; get; }
    public string content { set; get; }
    public string progress { set; get; }
}
// 此段代码防止在窗体 cs 文件的初始化构造函数即可
// 此处代码仅仅做一个范例,你可以循环执行以下代码创建多个圆形进度条
// 也可以通过 WEB SERVICE 获取所需的数据,然后循环创建进度条
ProgressBar pb = new ProgressBar();
ProgressData pd = new ProgressData();

pb.Value = 240;
pb.Style = (Style)FindResource("styleProgressBar");
pb.Foreground = new SolidColorBrush(Color.FromRgb(0,255,0));
pb.Background = new SolidColorBrush(Color.FromRgb(255,255,255));

pd.title    = "XX001";
pd.content  = "线路板";
pd.progress = "剩余 13 天";

pb.DataContext = pd;
uiProgressBars.Children.Add(pb);