Barra de progreso radial / medidor de WPF (es decir, medidor de batería)

Estoy trabajando en una aplicación Unified Fitness para Windows 8.1 y Windows Phone 8.1. Lo ideal sería que una de las vistas principales contara con un medidor de progreso diario. El problema es que no he podido obtener un medidor o medidor real. Lo que me gustaría tener es simplemente una barra de progreso radial o algo similar a los medidores / medidores de batería en aplicaciones de batería comunes en la tienda de Windows Phone. Por lo que puedo decir, WPF / VS 2013 no ofrece este tipo de componente de fábrica. Sé que Telerik y algunos otros terceros ofrecen algo similar, pero prefiero usar algo de código abierto o comstackrlo yo mismo.

¿Alguien sabe de los nuevos componentes de código abierto que funcionan con .NET 4.5 y WPF o tiene ejemplos de cómo podría construir mi propio componente?

Hasta ahora, lo que he encontrado es similar a este enlace: Medidores para WPF

Pero espero usar algo similar a esto: introduzca la descripción de la imagen aquí

Puedes construir algo así por ti mismo. En primer lugar, necesitas un arco:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Shapes; using System.Windows.Media; using System.Windows; ... public class Arc : Shape { public double StartAngle { get { return (double)GetValue(StartAngleProperty); } set { SetValue(StartAngleProperty, value); } } // Using a DependencyProperty as the backing store for StartAngle. This enables animation, styling, binding, etc... public static readonly DependencyProperty StartAngleProperty = DependencyProperty.Register("StartAngle", typeof(double), typeof(Arc), new UIPropertyMetadata(0.0, new PropertyChangedCallback(UpdateArc))); public double EndAngle { get { return (double)GetValue(EndAngleProperty); } set { SetValue(EndAngleProperty, value); } } // Using a DependencyProperty as the backing store for EndAngle. This enables animation, styling, binding, etc... public static readonly DependencyProperty EndAngleProperty = DependencyProperty.Register("EndAngle", typeof(double), typeof(Arc), new UIPropertyMetadata(90.0, new PropertyChangedCallback(UpdateArc))); //This controls whether or not the progress bar goes clockwise or counterclockwise public SweepDirection Direction { get { return (SweepDirection) GetValue(DirectionProperty); } set { SetValue(DirectionProperty, value);} } public static readonly DependencyProperty DirectionProperty = DependencyProperty.Register("Direction", typeof (SweepDirection), typeof (Arc), new UIPropertyMetadata(SweepDirection.Clockwise)); //rotate the start/endpoint of the arc a certain number of degree in the direction //ie. if you wanted it to be at 12:00 that would be 270 Clockwise or 90 counterclockwise public double OriginRotationDegrees { get { return (double) GetValue(OriginRotationDegreesProperty); } set { SetValue(OriginRotationDegreesProperty, value);} } public static readonly DependencyProperty OriginRotationDegreesProperty = DependencyProperty.Register("OriginRotationDegrees", typeof (double), typeof (Arc), new UIPropertyMetadata(270.0, new PropertyChangedCallback(UpdateArc))); protected static void UpdateArc(DependencyObject d, DependencyPropertyChangedEventArgs e) { Arc arc = d as Arc; arc.InvalidateVisual(); } protected override Geometry DefiningGeometry { get { return GetArcGeometry(); } } protected override void OnRender(System.Windows.Media.DrawingContext drawingContext) { drawingContext.DrawGeometry(null, new Pen(Stroke, StrokeThickness), GetArcGeometry()); } private Geometry GetArcGeometry() { Point startPoint = PointAtAngle(Math.Min(StartAngle, EndAngle), Direction); Point endPoint = PointAtAngle(Math.Max(StartAngle, EndAngle), Direction); Size arcSize = new Size(Math.Max(0, (RenderSize.Width - StrokeThickness) / 2), Math.Max(0, (RenderSize.Height - StrokeThickness) / 2)); bool isLargeArc = Math.Abs(EndAngle - StartAngle) > 180; StreamGeometry geom = new StreamGeometry(); using (StreamGeometryContext context = geom.Open()) { context.BeginFigure(startPoint, false, false); context.ArcTo(endPoint, arcSize, 0, isLargeArc, Direction, true, false); } geom.Transform = new TranslateTransform(StrokeThickness / 2, StrokeThickness / 2); return geom; } private Point PointAtAngle(double angle, SweepDirection sweep) { double translatedAngle = angle + OriginRotationDegrees; double radAngle = translatedAngle * (Math.PI / 180); double xr = (RenderSize.Width - StrokeThickness) / 2; double yr = (RenderSize.Height - StrokeThickness) / 2; double x = xr + xr * Math.Cos(radAngle); double y = yr * Math.Sin(radAngle); if (sweep == SweepDirection.Counterclockwise) { y = yr - y; } else { y = yr + y; } return new Point(x, y); } } 

Este arco tiene un StartAngle y un EndAngle. Para convertir de un progreso de una barra de progreso a estos angularjs, necesita un convertidor:

 using System; using System.Collections.Generic; using System.Linq; using System.Text; ... public class ProgressToAngleConverter : System.Windows.Data.IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { double progress = (double)values[0]; System.Windows.Controls.ProgressBar bar = values[1] as System.Windows.Controls.ProgressBar; return 359.999 * (progress / (bar.Maximum - bar.Minimum)); } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } 

Está bien. Eso fue todo lo que necesitas. Ahora puedes escribir tu XAML. Eso podría ser algo así:

                 

Ahora simplemente tome el ProgressBarStyle , modifíquelo y aplíquelo a la barra de progreso que desee.

Finalmente, obtendrás algo como esto. ¡Que te diviertas!

EDITAR: Necesita las siguientes referencias (le recomendaría, para crear un proyecto WPF nuevo y vacío):

  • WindowsBase
  • PresentaciónCore
  • PresentaciónFramework

EDITAR: Con el fin de controlar la dirección de rotación, así como la posición para comenzar el progreso, agregué dos propiedades de dependencia: Direction OriginRotationDegrees

introduzca la descripción de la imagen aquí