我需要帮助实现这样的循环进度条:
如何通过增加Value
属性来实现圆圈填充?
答案 0 :(得分:22)
您有几个选项 - 第一个是模板ProgressBar
控件。事实证明这有点棘手。我写了一篇博文,介绍了如何use an attached ViewModel to achieve the required effect。
另一种方法是从头开始创建自己的控件。您可以执行以下操作:
答案 1 :(得分:12)
这有点棘手,但并非不可能。这是我使用平滑动画指导的实现。应使用值转换器来创建CircularProgressBar。
<强> CircularProgressBar.cs 强>
public partial class CircularProgressBar : ProgressBar
{
public CircularProgressBar()
{
this.ValueChanged += CircularProgressBar_ValueChanged;
}
void CircularProgressBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
CircularProgressBar bar = sender as CircularProgressBar;
double currentAngle = bar.Angle;
double targetAngle = e.NewValue / bar.Maximum * 359.999;
DoubleAnimation anim = new DoubleAnimation(currentAngle, targetAngle, TimeSpan.FromMilliseconds(500));
bar.BeginAnimation(CircularProgressBar.AngleProperty, anim, HandoffBehavior.SnapshotAndReplace);
}
public double Angle
{
get { return (double)GetValue(AngleProperty); }
set { SetValue(AngleProperty, value); }
}
// Using a DependencyProperty as the backing store for Angle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AngleProperty =
DependencyProperty.Register("Angle", typeof(double), typeof(CircularProgressBar), new PropertyMetadata(0.0));
public double StrokeThickness
{
get { return (double)GetValue(StrokeThicknessProperty); }
set { SetValue(StrokeThicknessProperty, value); }
}
// Using a DependencyProperty as the backing store for StrokeThickness. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StrokeThicknessProperty =
DependencyProperty.Register("StrokeThickness", typeof(double), typeof(CircularProgressBar), new PropertyMetadata(10.0));
}
<强> AngleToPointConverter.cs 强>
class AngleToPointConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double angle = (double)value;
double radius = 50;
double piang = angle * Math.PI / 180;
double px = Math.Sin(piang) * radius + radius;
double py = -Math.Cos(piang) * radius + radius;
return new Point(px, py);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
<强> AngleToIsLargeConverter.cs 强>
class AngleToIsLargeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double angle = (double)value;
return angle > 180;
}
public object ConvertBack(object value, Type targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
<强>的App.xaml 强>
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
xmlns:my="clr-namespace:WpfApplication1">
<Application.Resources>
<my:AngleToPointConverter x:Key="prConverter"/>
<my:AngleToIsLargeConverter x:Key="isLargeConverter"/>
<Style x:Key="circularProgressBar" TargetType="my:CircularProgressBar">
<Setter Property="Value" Value="10"/>
<Setter Property="Maximum" Value="100"/>
<Setter Property="StrokeThickness" Value="10"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="my:CircularProgressBar">
<Canvas Width="100" Height="100">
<Ellipse Width="100" Height="100" Stroke="LightGray"
StrokeThickness="1"/>
<Path Stroke="{TemplateBinding Background}"
StrokeThickness="{TemplateBinding StrokeThickness}">
<Path.Data>
<PathGeometry>
<PathFigure x:Name="fig" StartPoint="50,0">
<ArcSegment RotationAngle="0" SweepDirection="Clockwise"
Size="50,50"
Point="{Binding Path=Angle, Converter={StaticResource prConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType=ProgressBar}}"
IsLargeArc="{Binding Path=Angle, Converter={StaticResource isLargeConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType=ProgressBar}}"
>
</ArcSegment>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<Border Width="100" Height="100">
<TextBlock Foreground="Gray" HorizontalAlignment="Center" VerticalAlignment="Center"
Text="{Binding Path=Value, StringFormat={}%{0},
RelativeSource={RelativeSource TemplatedParent}}"
FontSize="{TemplateBinding FontSize}"/>
</Border>
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
可以通过添加更多属性(如InnerRadius,Radius等)来进行更多自定义。
答案 2 :(得分:8)
我知道这是一个老问题,但无论如何,这是我的解决方案:
FOR WINFORMS:
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public class CircularProgressBar : Control
{
/* CREDITS:
* Autor: Sajjad Arif Gul / October 12, 2016 / C#, Source Codes
* https://www.csharpens.com/c-sharp/circular-progress-bar-in-c-sharp-windows-form-applications-23/
* Modified by Jhollman Chacon, 2017 */
#region Enums
public enum _ProgressShape
{
Round,
Flat
}
#endregion
#region Variables
private long _Value;
private long _Maximum = 100;
private Color _ProgressColor1 = Color.Orange;
private Color _ProgressColor2 = Color.Orange;
private Color _LineColor = Color.Silver;
private _ProgressShape ProgressShapeVal;
#endregion
#region Custom Properties
public long Value
{
get { return _Value; }
set
{
if (value > _Maximum)
value = _Maximum;
_Value = value;
Invalidate();
}
}
public long Maximum
{
get { return _Maximum; }
set
{
if (value < 1)
value = 1;
_Maximum = value;
Invalidate();
}
}
public Color ProgressColor1
{
get { return _ProgressColor1; }
set
{
_ProgressColor1 = value;
Invalidate();
}
}
public Color ProgressColor2
{
get { return _ProgressColor2; }
set
{
_ProgressColor2 = value;
Invalidate();
}
}
public Color LineColor
{
get { return _LineColor; }
set
{
_LineColor = value;
Invalidate();
}
}
public _ProgressShape ProgressShape
{
get { return ProgressShapeVal; }
set
{
ProgressShapeVal = value;
Invalidate();
}
}
#endregion
#region EventArgs
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
SetStandardSize();
}
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
SetStandardSize();
}
protected override void OnPaintBackground(PaintEventArgs p)
{
base.OnPaintBackground(p);
}
#endregion
#region Methods
public CircularProgressBar()
{
Size = new Size(130, 130);
Font = new Font("Segoe UI", 15);
MinimumSize = new Size(100, 100);
DoubleBuffered = true;
Value = 57;
ProgressShape = _ProgressShape.Flat;
this.ForeColor = Color.DimGray;
}
private void SetStandardSize()
{
int _Size = Math.Max(Width, Height);
Size = new Size(_Size, _Size);
}
public void Increment(int Val)
{
this._Value += Val;
Invalidate();
}
public void Decrement(int Val)
{
this._Value -= Val;
Invalidate();
}
#endregion
#region Events
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (Bitmap bitmap = new Bitmap(this.Width, this.Height))
{
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.Clear(this.BackColor);
// Dibuja la Linea
using (Pen pen2 = new Pen(LineColor))
{
graphics.DrawEllipse(pen2, 0x18 - 6, 0x18 - 6, (this.Width - 0x30) + 12, (this.Height - 0x30) + 12);
}
//Dibuja la Barra de Progreso
using (LinearGradientBrush brush = new LinearGradientBrush(this.ClientRectangle, this._ProgressColor1, this._ProgressColor2, LinearGradientMode.ForwardDiagonal))
{
using (Pen pen = new Pen(brush, 14f))
{
switch (this.ProgressShapeVal)
{
case _ProgressShape.Round:
pen.StartCap = LineCap.Round;
pen.EndCap = LineCap.Round;
break;
case _ProgressShape.Flat:
pen.StartCap = LineCap.Flat;
pen.EndCap = LineCap.Flat;
break;
}
//Aqui se dibuja el Progreso
graphics.DrawArc(pen, 0x12, 0x12, (this.Width - 0x23) - 2, (this.Height - 0x23) - 2, -90, (int)Math.Round((double)((360.0 / ((double)this._Maximum)) * this._Value)));
}
}
//Dibuja el Texto de Progreso:
Brush FontColor = new SolidBrush(this.ForeColor);
SizeF MS = graphics.MeasureString(Convert.ToString(Convert.ToInt32((100 / _Maximum) * _Value)), Font);
graphics.DrawString(Convert.ToString(Convert.ToInt32((100 / _Maximum) * _Value)), Font, FontColor, Convert.ToInt32(Width / 2 - MS.Width / 2), Convert.ToInt32(Height / 2 - MS.Height / 2));
e.Graphics.DrawImage(bitmap, 0, 0);
graphics.Dispose();
bitmap.Dispose();
}
}
}
#endregion
}
实现:
答案 3 :(得分:6)
你看过ValueConverter
了吗?您可以使用TemplateBinding
绑定到模板中的Value属性,并使用适当的值转换器将值更改为wwhts对循环进度条很有用。
编辑:
在模板中:
添加黄色圆圈填充。
在顶部添加另一个圆圈,颜色为橙色。
使用值转换器(或多值转换器)为2中添加的圆返回剪裁几何体(可能使用弧段)。
将圆圈剪裁为2.将几何体返回到3。
Downvoter给了我我的回复。