Per altre informazioni scrivi a fabriziocaldarelli@negusweb.it
Ring Chart in WPF CSharp WinRT
Il Ring Chart è il classico grafico a forma di ciambella, cioè dove è evidenziata l'area tra due circonferenze concentriche con raggi differenti.
Il pacchetto con l'esempio è costituito fondamentalmente da 2 files:
Main.xaml: contiene semplicemente l'oggetto RingChart e nell'initialize il popolamento dell'oggetto stesso, attraverso 2 modalità; la prima indiretta cioè attraverso l'assegnazione di un valore all'area (diciamo che è quello più umano) e poi quello diretto dove si vanno ad esplicitare l'angolo iniziale e finale.
Il controllo è personalizzabile attraverso il colore di ciascuna area definita, il colore e l'eventuale grandezza del bordo.
RingChart.xaml
<UserControl x:Class="Negusweb.Controls.RingChart" DataContext="{Binding RelativeSource={RelativeSource Self}}" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:RingChart" xmlns:winrtToolkit="using:WinRTXamlToolkit.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400" Name="ucRingChart" > <Grid> <ItemsControl ItemsSource="{Binding ChartItemsSource}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <Grid /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <winrtToolkit:RingSlice Fill="{Binding Fill}" Stroke="{Binding Stroke}" StrokeThickness="{Binding StrokeThickness}" InnerRadius="{Binding Path=DataContext.InnerRadius,ElementName=ucRingChart}" Radius="{Binding Path=DataContext.Radius,ElementName=ucRingChart}" StartAngle="{Binding StartAngle}" EndAngle="{Binding EndAngle}" /> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </Grid> </UserControl>
RingChart.xaml
using System; using System.Collections.Generic; using System.IO; using System.Linq; using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls.Primitives; using Windows.UI.Xaml.Data; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; // The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 namespace Negusweb.Controls { public sealed partial class RingChart : UserControl { public class RingChartItem { public double StartAngle { get; set; } public double EndAngle { get; set; } public Brush Fill { get; set; } public Brush Stroke { get; set; } public double StrokeThickness { get; set; } public RingChartItem(double startAngleInput, double endAngleInput, Brush fillInput) { this.StartAngle = startAngleInput; this.EndAngle = endAngleInput; this.Fill = fillInput; this.Stroke = null; this.StrokeThickness = 0; } public static RingChartItem CreaDaValore(double valore, double totale, Brush fillInput) { double temp = valore * 360 / totale; RingChartItem rci = new RingChartItem(0, temp, fillInput); return rci; } } #region ChartItemsSource /// <summary> /// The start angle property. /// </summary> public static readonly DependencyProperty ChartItemsSourceProperty = DependencyProperty.Register( "ChartItemsSource", typeof(List<RingChartItem>), typeof(RingChart), new PropertyMetadata( null, OnChartItemsSourceChanged)); /// <summary> /// Gets or sets the start angle. /// </summary> /// <value> /// The start angle. /// </value> public List<RingChartItem> ChartItemsSource { get { return (List<RingChartItem>)GetValue(ChartItemsSourceProperty); } set { SetValue(ChartItemsSourceProperty, value); } } private static void OnChartItemsSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { var target = (RingChart)sender; var oldStartAngle = (List<RingChartItem>)e.OldValue; var newStartAngle = (List<RingChartItem>)e.NewValue; target.OnChartItemsSourceChanged(oldStartAngle, newStartAngle); } private void OnChartItemsSourceChanged(List<RingChartItem> oldStartAngle, List<RingChartItem> newStartAngle) { //UpdatePath(); int a = 0; } #endregion #region Radius /// <summary> /// The radius property /// </summary> public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register( "Radius", typeof(double), typeof(RingChart), new PropertyMetadata( 0d, OnRadiusChanged)); /// <summary> /// Gets or sets the outer radius. /// </summary> /// <value> /// The outer radius. /// </value> public double Radius { get { return (double)GetValue(RadiusProperty); } set { SetValue(RadiusProperty, value); } } private static void OnRadiusChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { var target = (RingChart)sender; var oldRadius = (double)e.OldValue; var newRadius = (double)e.NewValue; target.OnRadiusChanged(oldRadius, newRadius); } private void OnRadiusChanged(double oldRadius, double newRadius) { this.Width = this.Height = 2 * Radius; //UpdatePath(); } #endregion #region InnerRadius /// <summary> /// The inner radius property /// </summary> public static readonly DependencyProperty InnerRadiusProperty = DependencyProperty.Register( "InnerRadius", typeof(double), typeof(RingChart), new PropertyMetadata( 0d, OnInnerRadiusChanged)); /// <summary> /// Gets or sets the inner radius. /// </summary> /// <value> /// The inner radius. /// </value> public double InnerRadius { get { return (double)GetValue(InnerRadiusProperty); } set { SetValue(InnerRadiusProperty, value); } } private static void OnInnerRadiusChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { var target = (RingChart)sender; var oldInnerRadius = (double)e.OldValue; var newInnerRadius = (double)e.NewValue; target.OnInnerRadiusChanged(oldInnerRadius, newInnerRadius); } private void OnInnerRadiusChanged(double oldInnerRadius, double newInnerRadius) { if (newInnerRadius < 0) { throw new ArgumentException("InnerRadius can't be a negative value.", "InnerRadius"); } //UpdatePath(); } #endregion #region EmptyBrush /// <summary> /// The inner radius property /// </summary> public static readonly DependencyProperty EmptyBrushProperty = DependencyProperty.Register( "EmptyBrush", typeof(Brush), typeof(RingChart), new PropertyMetadata( new SolidColorBrush(Color.FromArgb(0xFF, 0x77, 0x77, 0x77)), OnEmptyBrushChanged)); /// <summary> /// Gets or sets the inner radius. /// </summary> /// <value> /// The inner radius. /// </value> public Brush EmptyBrush { get { return (Brush)GetValue(EmptyBrushProperty); } set { SetValue(EmptyBrushProperty, value); } } private static void OnEmptyBrushChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { var target = (RingChart)sender; var oldInnerRadius = (Brush)e.OldValue; var newInnerRadius = (Brush)e.NewValue; target.OnEmptyBrushChanged(oldInnerRadius, newInnerRadius); } private void OnEmptyBrushChanged(Brush oldInnerRadius, Brush newInnerRadius) { //UpdatePath(); } #endregion #region IsEmptyBrushDrawn /// <summary> /// The inner radius property /// </summary> public static readonly DependencyProperty IsEmptyBrushDrawnProperty = DependencyProperty.Register( "IsEmptyBrushDrawn", typeof(bool), typeof(RingChart), new PropertyMetadata( true, OnEmptyBrushDrawnChanged)); /// <summary> /// Gets or sets the inner radius. /// </summary> /// <value> /// The inner radius. /// </value> public bool IsEmptyBrushDrawn { get { return (bool)GetValue(IsEmptyBrushDrawnProperty); } set { SetValue(IsEmptyBrushDrawnProperty, value); } } private static void OnEmptyBrushDrawnChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { var target = (RingChart)sender; var oldInnerRadius = (bool)e.OldValue; var newInnerRadius = (bool)e.NewValue; target.OnEmptyBrushDrawnChanged(oldInnerRadius, newInnerRadius); } private void OnEmptyBrushDrawnChanged(bool oldInnerRadius, bool newInnerRadius) { //UpdatePath(); } #endregion public double? StartAngle { get; set; } public RingChart() { this.InitializeComponent(); } public void AggiornaDaListaItemValori(List<RingChartItem> lstInput) { double dx = (StartAngle != null) ? StartAngle.Value : 0; double angoloIniziale = dx; double angoloFinale = 0; List<RingChartItem> lstOut = new List<RingChartItem>(); for (int k = 0; k < lstInput.Count; k++) { RingChartItem rci = lstInput[k]; if ((k == 0) && (angoloIniziale == 0)) { angoloIniziale = rci.StartAngle; } angoloFinale = angoloIniziale + rci.EndAngle; lstOut.Add(new RingChartItem(angoloIniziale, angoloFinale, rci.Fill)); angoloIniziale = angoloFinale; } if (IsEmptyBrushDrawn) { if (angoloIniziale < 360) { angoloFinale = 360; lstOut.Add(new RingChartItem(angoloIniziale, angoloFinale, EmptyBrush)); } } this.ChartItemsSource = lstOut; } } }
Il risultato è quello che segue
Allegati
- Codice sorgente di Ring Chart Demo[[Category::WinRT]]