服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - WPF实现圆形进度条的示例代码

WPF实现圆形进度条的示例代码

2023-02-28 13:27驚鏵 C#

这篇文章主要为大家详细介绍了WPF如何实现圆形的进度条,文中的示例代码讲解详细,对我们学习或工作有一定帮助,感兴趣的小伙伴可以了解一下

WPF 实现圆形进度条

  • 框架使用.NET40
  • Visual Studio 2019;
  • CircularProgressBar 继承 ProgressBar,在 XAML 中创建两个 Path 的 Data 设置 ArcSegment 修改第二个控件的 Point ,设置 StartPoint = new Point(Size.Width, 0) 设置起点。
  • 创建依赖属性 Angle 作为修改 ArcSegment 的 Point 作为进度条的圆的闭合。
  • 当进度条 ValueChanged 时创建 DoubleAnimation 动画,修改 Angle 。

示例代码

1) CircularProgressBar.xaml 代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:controls="clr-namespace:WPFDevelopers.Controls"
                    xmlns:convert="clr-namespace:WPFDevelopers.Converts">
    
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Basic/ControlBasic.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    <convert:AngleToPointConverter x:Key="prConverter"/>
    <convert:AngleToIsLargeConverter x:Key="isLargeConverter"/>
    <Style TargetType="{x:Type controls:CircularProgressBar}" BasedOn="{StaticResource ControlBasicStyle}">
        <Setter Property="Maximum" Value="100"/>
        <Setter Property="StrokeThickness" Value="10"/>
        <Setter Property="Foreground" Value="{DynamicResource InfoSolidColorBrush}"/>
        <Setter Property="Background" Value="{DynamicResource PrimaryNormalSolidColorBrush}"/>
        <Setter Property="HorizontalAlignment" Value="Center"/>
        <Setter Property="VerticalAlignment" Value="Center"/>
        <!--<Setter Property="Width" Value="100"/>
        <Setter Property="Height" Value="100"/>-->
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type controls:CircularProgressBar}">
                    <controls:SmallPanel Width="{Binding ElementName=PART_Path,Path=ActualWidth}"
                            Height="{Binding ElementName=PART_Path,Path=ActualHeight}"
                            HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
                            VerticalAlignment="{TemplateBinding VerticalAlignment}">
                        <Canvas>
                            <Path Stroke="{TemplateBinding BorderBrush}"
                              StrokeThickness="{TemplateBinding BrushStrokeThickness}"
                                  x:Name="PART_Path">
                                <Path.Data>
                                    <PathGeometry>
                                        <PathFigure x:Name="PART_PathFigure">
                                            <ArcSegment SweepDirection="Clockwise"
                                                    IsLargeArc="True"
                                                    x:Name="PART_ArcSegment">
                                            </ArcSegment>
                                        </PathFigure>
                                    </PathGeometry>
                                </Path.Data>
                            </Path>
                            <Path Stroke="{TemplateBinding Background}"
                              StrokeThickness="{TemplateBinding StrokeThickness}">
                                <Path.Data>
                                    <PathGeometry>
                                        <PathFigure x:Name="PART_PathFigureAngle">
                                            <ArcSegment SweepDirection="Clockwise"
                                                    IsLargeArc="{Binding Path=Angle, Converter={StaticResource isLargeConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType=ProgressBar}}"
                                                    x:Name="PART_ArcSegmentAngle">
                                                <ArcSegment.Point>
                                                    <MultiBinding Converter="{StaticResource prConverter}">
                                                        <Binding Path="Angle" RelativeSource="{RelativeSource FindAncestor, AncestorType=ProgressBar}"/>
                                                        <Binding Path="Size" RelativeSource="{RelativeSource FindAncestor, AncestorType=ProgressBar}"/>
                                                    </MultiBinding>
                                                </ArcSegment.Point>
                                            </ArcSegment>
                                        </PathFigure>
                                    </PathGeometry>
                                </Path.Data>
                            </Path>
                        </Canvas>
                        <TextBlock Foreground="{TemplateBinding Foreground}"
                                   Text="{Binding Path=Value, StringFormat={}{0}%,
                                RelativeSource={RelativeSource TemplatedParent}}"
                                   FontSize="{TemplateBinding FontSize}"
                                   VerticalAlignment="Center"
                                   HorizontalAlignment="Center"
                                   x:Name="PART_TextBlock"/>
                    </controls:SmallPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

2) CircularProgressBar.xaml.cs 代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
 
namespace WPFDevelopers.Controls
{
    [TemplatePart(Name = ArcSegmentTemplateName, Type = typeof(ArcSegment))]
    [TemplatePart(Name = ArcSegmentAngleTemplateName, Type = typeof(ArcSegment))]
    [TemplatePart(Name = PathFigureTemplateName, Type = typeof(PathFigure))]
    [TemplatePart(Name = PathFigureAngleTemplateName, Type = typeof(PathFigure))]
    [TemplatePart(Name = TextBlockTemplateName, Type = typeof(TextBlock))]
    public class CircularProgressBar : ProgressBar
    {
        private const string ArcSegmentTemplateName = "PART_ArcSegment";
        private const string ArcSegmentAngleTemplateName = "PART_ArcSegmentAngle";
        private const string PathFigureTemplateName = "PART_PathFigure";
        private const string PathFigureAngleTemplateName = "PART_PathFigureAngle";
        private const string TextBlockTemplateName = "PART_TextBlock";
        private ArcSegment _arcSegment, _arcSegmentAngle;
        private PathFigure _pathFigure, _pathFigureAngle;
        private TextBlock _textBlock;
 
 
        public static readonly DependencyProperty SizeProperty =
           DependencyProperty.Register("Size"typeof(Size), typeof(CircularProgressBar),
               new PropertyMetadata(new Size(50,50)));
        public static readonly DependencyProperty AngleProperty =
            DependencyProperty.Register("Angle"typeof(double), typeof(CircularProgressBar),
                new PropertyMetadata(0.0));
 
        public static readonly DependencyProperty StrokeThicknessProperty =
            DependencyProperty.Register("StrokeThickness"typeof(double), typeof(CircularProgressBar),
                new PropertyMetadata(10.0));
 
        public static readonly DependencyProperty BrushStrokeThicknessProperty =
            DependencyProperty.Register("BrushStrokeThickness"typeof(double), typeof(CircularProgressBar),
                new PropertyMetadata(1.0));
 
        public CircularProgressBar()
        {
            ValueChanged += CircularProgressBar_ValueChanged;
        }
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
           
            if (Size.Width != Size.Height)
            {
                var max = Math.Max(Size.Width, Size.Height);
                Size = new Size(max, max);
            }
           
            _pathFigure = GetTemplateChild(PathFigureTemplateName) as PathFigure;
            _pathFigureAngle = GetTemplateChild(PathFigureAngleTemplateName) as PathFigure;
            _pathFigure.StartPoint = new Point(Size.Width, 0);
            _pathFigureAngle.StartPoint = new Point(Size.Width, 0);
            _arcSegment = GetTemplateChild(ArcSegmentTemplateName) as ArcSegment;
            _arcSegment.Size = Size;
            _arcSegment.Point = new Point(Size.Width - 0.000872664626, 7.61543361704753E-09);
            _arcSegmentAngle = GetTemplateChild(ArcSegmentAngleTemplateName) as ArcSegment;
            _arcSegmentAngle.Size = Size;
            _textBlock = GetTemplateChild(TextBlockTemplateName) as TextBlock;
            if (Size.Width < 15)
            {
                FontSize = 8;
            }
        }
        
        public Size Size
        {
            get => (Size)GetValue(SizeProperty);
            set => SetValue(SizeProperty, value);
        }
 
        public double Angle
        {
            get => (double)GetValue(AngleProperty);
            set => SetValue(AngleProperty, value);
        }
 
        public double StrokeThickness
        {
            get => (double)GetValue(StrokeThicknessProperty);
            set => SetValue(StrokeThicknessProperty, value);
        }
 
        public double BrushStrokeThickness
        {
            get => (double)GetValue(BrushStrokeThicknessProperty);
            set => SetValue(BrushStrokeThicknessProperty, value);
        }
 
        private void CircularProgressBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            var bar = sender as CircularProgressBar;
            var currentAngle = bar.Angle;
            var targetAngle = e.NewValue / bar.Maximum * 359.999;
            var anim = new DoubleAnimation(currentAngle, targetAngle, TimeSpan.FromMilliseconds(500));
            bar.BeginAnimation(AngleProperty, anim, HandoffBehavior.SnapshotAndReplace);
        }
    }
}

3) AngleToPointConverter.cs 代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
 
namespace WPFDevelopers.Converts
{
    internal class AngleToPointConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            var angle = (double)values[0];
            var size = (Size)values[1];
            var radius = (double)size.Height;
            var piang = angle * Math.PI / 180;
 
            var px = Math.Sin(piang) * radius + radius;
            var py = -Math.Cos(piang) * radius + radius;
            return new Point(px, py);
        }
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

4) AngleToIsLargeConverter.cs 代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System;
using System.Globalization;
using System.Windows.Data;
 
namespace WPFDevelopers.Converts
{
    internal class AngleToIsLargeConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var angle = (double)value;
            return angle > 180;
        }
 
        public object ConvertBack(object value, Type targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

5) CircularMenuExample.xaml 代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.CircularMenuExample"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews"
             xmlns:wpfdev="https://github.com/WPFDevelopersOrg/WPFDevelopers"
             xmlns:controls="clr-namespace:WPFDevelopers.Samples.Controls"
             mc:Ignorable="d"
             d:DesignHeight="450" d:DesignWidth="800">
    <controls:CodeViewer>
        <StackPanel Background="Black">
        <TextBlock Text="微信公众号:WPFDevelopers" FontSize="40"
                           Foreground="#A9CC32" FontWeight="Bold"
                           Margin="50,10,0,20"/>
        <wpfdev:CircularMenu ItemsSource="{Binding MenuArray,RelativeSource={RelativeSource AncestorType=local:CircularMenuExample}}"
                             SelectionChanged="CircularMenu_SelectionChanged"/>
    </StackPanel>
        <controls:CodeViewer.SourceCodes>
            <controls:SourceCodeModel
                CodeSource="/WPFDevelopers.SamplesCode;component/ExampleViews/CircularMenuExample.xaml"
                CodeType="Xaml"/>
            <controls:SourceCodeModel
                CodeSource="/WPFDevelopers.SamplesCode;component/ExampleViews/CircularMenuExample.xaml.cs"
                CodeType="CSharp"/>
        </controls:CodeViewer.SourceCodes>
    </controls:CodeViewer>
</UserControl>

效果图

WPF实现圆形进度条的示例代码

到此这篇关于WPF实现圆形进度条的示例代码的文章就介绍到这了,更多相关WPF进度条内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://mp.weixin.qq.com/s/1ql9MCQqK2TfKGIoBtYXVw

延伸 · 阅读

精彩推荐
  • C#大家应该掌握的多线程编程

    大家应该掌握的多线程编程

    这篇文章主要介绍了大家应该掌握的多线程编程,具有一定借鉴价值,需要的朋友可以参考下...

    Helius-黑牛4642022-02-17
  • C#Unity3D制作序列帧动画的方法

    Unity3D制作序列帧动画的方法

    这篇文章主要为大家详细介绍了Unity3D制作序列帧动画的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    qq_339945665752022-03-10
  • C#【C#基础】Substring截取字符串的方法小结(推荐)

    【C#基础】Substring截取字符串的方法小结(推荐)

    这篇文章主要介绍了Substring截取字符串方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面...

    大白快跑89402022-07-22
  • C#unity 切换场景不销毁物体问题的解决

    unity 切换场景不销毁物体问题的解决

    这篇文章主要介绍了unity 切换场景不销毁物体问题的解决方案,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    xmhwjzabc11842022-11-13
  • C#C#实现坦克大战游戏

    C#实现坦克大战游戏

    这篇文章主要为大家详细介绍了C#实现坦克大战游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    无名风沙4622022-09-22
  • C#如何使用C#在PDF文件添加图片印章

    如何使用C#在PDF文件添加图片印章

    文档中添加印章可以起一定的作用,比如,防止文件随意被使用,或者确保文档内容的安全性和权威性。C#添加图片印章其实也有很多实现方法,这里我使...

    C#教程网11342021-12-21
  • C#Unity实现简单摇杆的制作

    Unity实现简单摇杆的制作

    这篇文章主要为大家详细介绍了Unity实现简单摇杆的制作,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    Zero_LJ6112022-12-05
  • C#C#操作图片读取和存储SQLserver实现代码

    C#操作图片读取和存储SQLserver实现代码

    用C#将Image转换成byte[]并插入数据库/将图片数据从SQLserver中取出来并显示到pictureBox控件上,接下来将为你详细介绍下实现步骤,感兴趣的你可以参考下...

    C#教程网2962020-12-18