1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > WPF自定义控件(教程含源码)-圆形进度条 环形进度条

WPF自定义控件(教程含源码)-圆形进度条 环形进度条

时间:2019-07-27 14:23:26

相关推荐

WPF自定义控件(教程含源码)-圆形进度条 环形进度条

使用环形进度条显示用量百分比

控件效果如下

控件的关键属性如下:

Background:控制背景圆环的原色。

Stroke:控制进度圆环颜色、以及中间文本颜色。

Value:进度百分比,double类型,进度0~1.

控件前端xaml模板

<ResourceDictionary xmlns="/winfx//xaml/presentation"xmlns:x="/winfx//xaml"xmlns:local="clr-namespace:WPFCustomControl.Controls"><!--圆弧绑定转换,根据控件属性转换圆弧--><local:RingProgressArcConverter x:Key="ringProgressArcConverter" /><!--文本显示转换--><local:RingProgressValueConverter x:Key="ringProgressValueConverter" /><ControlTemplate x:Key="RingProgress_Template" TargetType="local:RingProgress"><Grid><Path StrokeThickness="{TemplateBinding StrokeThickness}" Stroke="{TemplateBinding Background}" StrokeEndLineCap="Round" StrokeStartLineCap="Round"HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="rootRing" ><Path.Data><MultiBinding Converter="{StaticResource ringProgressArcConverter}"><Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=local:RingProgress}" /><Binding Path="ActualHeight" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=local:RingProgress}" /><Binding Path="StrokeThickness" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=local:RingProgress}" /></MultiBinding></Path.Data></Path><Path StrokeThickness="{TemplateBinding StrokeThickness}" Stroke="{TemplateBinding Stroke}" StrokeEndLineCap="Round" StrokeStartLineCap="Round"HorizontalAlignment="Center" VerticalAlignment="Center"Width="{Binding ElementName=rootRing, Path=ActualWidth}"Height="{Binding ElementName=rootRing, Path=ActualHeight}"><Path.Data><MultiBinding Converter="{StaticResource ringProgressArcConverter}"><Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=local:RingProgress}" /><Binding Path="ActualHeight" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=local:RingProgress}" /><Binding Path="StrokeThickness" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=local:RingProgress}" /><Binding Path="Value" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=local:RingProgress}" /></MultiBinding></Path.Data></Path><TextBlock Foreground="{TemplateBinding Stroke}" FontSize="20" VerticalAlignment="Center" HorizontalAlignment="Center"Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=Value, Converter={StaticResource ringProgressValueConverter}}"/></Grid></ControlTemplate><!--设置 RingProgress 的默认样式--><Style TargetType="local:RingProgress"><Setter Property="Template" Value="{StaticResource RingProgress_Template}" /><Setter Property="Background" Value="#D2D2D2" /></Style></ResourceDictionary>

控件后台代码:

public partial class RingProgress : RangeBase{static RingProgress(){DefaultStyleKeyProperty.OverrideMetadata(typeof(RingProgress), new FrameworkPropertyMetadata(typeof(RingProgress)));}#region StrokeThickness 圆环描边宽度public static readonly DependencyProperty StrokeThicknessProperty =DependencyProperty.Register("StrokeThickness", typeof(double), typeof(RingProgress), new PropertyMetadata(10d));public double StrokeThickness{get { return (double)GetValue(StrokeThicknessProperty); }set { SetValue(StrokeThicknessProperty, value); }}#endregion#region Stroke 圆环描边颜色public static readonly DependencyProperty StrokeProperty =DependencyProperty.Register("Stroke", typeof(Brush), typeof(RingProgress), new PropertyMetadata(Brushes.Red));public Brush Stroke{get { return (Brush)GetValue(StrokeProperty); }set { SetValue(StrokeProperty, value); }}#endregion}internal class RingProgressArcConverter : IMultiValueConverter{// 注意,因为这里使用Path绘制圆环, 所以要把描边宽度大小考虑进去. 所有点的x、y偏移 半个描边宽度public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture){double value;if (values[0] is double width&& values[1] is double height&& width > 0 && height>0&& values[2] is double storkeWidth){width -= storkeWidth;height -= storkeWidth;value = values.Length == 4 ? System.Convert.ToDouble(values[3]) : 1d;if (value == 0) return "";var startAngle = -90d;var endAngle = Math.Min(value * 360 -90 , 269);var radius = Math.Min(width, height) * 0.5;var start = startAngle.AngleToPoint(radius, storkeWidth * 0.5);var end = endAngle.AngleToPoint(radius, storkeWidth * 0.5);var dataStr = $"M {start.X},{start.Y} A {radius},{radius} 0 {(endAngle - startAngle >= 180 ? 1 : 0)} 1 {end.X},{end.Y}";var converter = TypeDescriptor.GetConverter(typeof(Geometry));return (Geometry)converter.ConvertFrom(dataStr);}else{return "";}}public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture){throw new NotImplementedException();}}internal class RingProgressValueConverter : IValueConverter{public object Convert(object value, Type targetType, object parameter, CultureInfo culture){if (value is double v){return $"{v * 100}%";}else{return 0;}}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){throw new NotImplementedException();}}internal static class RingProgressExtension{/// <summary>/// 角度转为弧度/// </summary>/// <param name="a"></param>/// <returns></returns>public static double AngleToArc(this double a){return Math.PI * a / 180;}/// <summary>/// 角度及半径计算坐标点位置/// </summary>/// <param name="a"></param>/// <param name="radius"></param>/// <param name="offset"></param>/// <returns></returns>public static Point AngleToPoint(this double a, double radius, double offset = 0){return new Point(Math.Cos(a.AngleToArc()) * radius + radius + offset, Math.Sin(a.AngleToArc()) * radius + radius + offset);}}

使用示例

<UniformGrid Rows="2" Columns="2"><c:RingProgress Value="0.1" Margin="5" Stroke="#393D49" Background="#31BDEC" /><c:RingProgress Value="0.3" Margin="5" Stroke="Red" Background="#C2C2C2"/><c:RingProgress Value="0.5" Margin="5" Stroke="Red" Background="#C2C2C2"/><c:RingProgress Value="0.7" Margin="5" Stroke="Red" Background="#C2C2C2"/></UniformGrid>

有问题的请评论去留言。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。