WPF 在UI设计时常常需要圆型进度条如下图: (代码都上手敲出来的,喜欢的点个赞)
前台代码如下:
<UserControl x:Class="CircularProgressBar"
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"
mc:Ignorable="d"
d:DesignHeight="150" d:DesignWidth="150">
<Grid Name="layout" Height="{Binding RelativeSource={RelativeSource Self},Path=Width}">
<Ellipse Width="{Binding ElementName=layout,Path=ActualWidth}"
Height="{Binding RelativeSource={RelativeSource Self},Path=Width}"
StrokeThickness="8"
Stroke="{Binding BackColor,RelativeSource={RelativeSource AncestorType=UserControl,Mode=FindAncestor}}"
Name="backEllipse">
<Ellipse.Effect>
<DropShadowEffect ShadowDepth="0" Direction="0" Color="White" BlurRadius="5" />
</Ellipse.Effect>
</Ellipse>
<Path Name="path" StrokeStartLineCap="Round" StrokeEndLineCap="Round"
Stroke="{Binding ForeColor,RelativeSource={RelativeSource AncestorType=UserControl,Mode=FindAncestor}}"
StrokeThickness="6"/>
<Viewbox Margin="14">
<TextBlock VerticalAlignment="Center"
HorizontalAlignment="Center"
Foreground="{Binding RelativeSource={RelativeSource Self},Path=Foreground}"
Text="{Binding Value,StringFormat={}{0:F1} %, RelativeSource={RelativeSource AncestorType=UserControl,Mode=FindAncestor}}"
>
</TextBlock>
</Viewbox>
</Grid>
</UserControl>
后台需要添加一些依赖怪属性,同时需要对给定的值做验证:
public partial class CircularProgressBar : UserControl
{
public double Value
{
get { return (double)GetValue(ValueProperty); }
set
{
SetValue(ValueProperty, value);
}
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double), typeof(CircularProgressBar), new PropertyMetadata(0.0, new PropertyChangedCallback(OnPropertyChanged)));
public Brush BackColor
{
get { return (Brush)GetValue(BackColorProperty); }
set { SetValue(BackColorProperty, value); }
}
public static readonly DependencyProperty BackColorProperty =
DependencyProperty.Register("BackColor", typeof(Brush), typeof(CircularProgressBar), new PropertyMetadata(Brushes.LightGray));
public Brush ForeColor
{
get { return (Brush)GetValue(ForeColorProperty); }
set { SetValue(ForeColorProperty, value); }
}
public static readonly DependencyProperty ForeColorProperty =
DependencyProperty.Register("ForeColor", typeof(Brush), typeof(CircularProgressBar), new PropertyMetadata(Brushes.Orange));
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as CircularProgressBar).Value = Math.Min(100d, (d as CircularProgressBar).Value);//数据较验
(d as CircularProgressBar).UpdateValue();
}
public CircularProgressBar()
{
InitializeComponent();
this.SizeChanged += CircularProgressBar_SizeChanged;
}
private void CircularProgressBar_SizeChanged(object sender, SizeChangedEventArgs e)
{
this.UpdateValue();
}
通过Path画圆弧计算方法如下:
private void UpdateValue()
{
this.layout.Width = Math.Min(this.RenderSize.Width, this.RenderSize.Height);
this.layout.Height = Math.Min(this.RenderSize.Width, this.RenderSize.Height);
double radius = Math.Min(this.RenderSize.Width, this.RenderSize.Height) / 2;
if (radius <= 0) return;
double newX = 0.0, newY = 0.0;
newX = radius + (radius - 3) * Math.Cos((this.Value % 100.0 * 3.6 - 90) * Math.PI / 180);
newY = radius + (radius - 3) * Math.Sin((this.Value % 100.0 * 3.6 - 90) * Math.PI / 180);
string pathDataStr = "M{0} 3A{3} {3} 0 {4} 1 {1} {2}";
pathDataStr = string.Format(pathDataStr,
radius + 0.01,
newX,
newY,
radius - 3,
this.Value < 50 ? 0 : 1);
var converter = TypeDescriptor.GetConverter(typeof(Geometry));
this.path.Data = (Geometry)converter.ConvertFrom(pathDataStr);
}
}