WPF实现圆形进度条的示例代码
短信预约 -IT技能 免费直播动态提醒
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
代码如下:
<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
代码如下:
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
代码如下:
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
代码如下:
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
代码如下:
<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进度条内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341