I'm using System.Windows.Controls.DataVisualization.Charting to draw PieChart. But I don' know how to show the percentage/Value of each Pie Slice on the chart. Is that possible?
Adding percentage to a System.Windows.Controls.DataVisualization.Charting PieChart
is not so immediate, since there are no properties for managing labels.
Anyway there are some ways to reach the goal. I wrote an article on my blog to describe the one I used.
The first step is to create a custom PieDataPoint
class:
public class PieDataPoint : System.Windows.Controls.DataVisualization.Charting.PieDataPoint
{
public static readonly DependencyProperty TextedGeometryProperty =
DependencyProperty.Register("TextedGeometry", typeof(Geometry), typeof(PieDataPoint));
public Geometry TextedGeometry
{
get { return (Geometry)GetValue(TextedGeometryProperty); }
set { SetValue(TextedGeometryProperty, value); }
}
static PieDataPoint()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PieDataPoint),
new FrameworkPropertyMetadata(typeof(PieDataPoint)));
}
public PieDataPoint()
{
DependencyPropertyDescriptor dependencyPropertyDescriptor
= DependencyPropertyDescriptor.FromProperty(GeometryProperty, GetType());
dependencyPropertyDescriptor.AddValueChanged(this, OnGeometryValueChanged);
}
private double LabelFontSize
{
get
{
FrameworkElement parentFrameworkElement = Parent as FrameworkElement;
return Math.Max(8, Math.Min(parentFrameworkElement.ActualWidth,
parentFrameworkElement.ActualHeight) / 30);
}
}
private void OnGeometryValueChanged(object sender, EventArgs arg)
{
Point point;
FormattedText formattedText;
CombinedGeometry combinedGeometry = new CombinedGeometry();
combinedGeometry.GeometryCombineMode = GeometryCombineMode.Exclude;
formattedText = new FormattedText(FormattedRatio,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface("Arial"),
LabelFontSize,
Brushes.White);
if (ActualRatio == 1)
{
EllipseGeometry ellipseGeometry = Geometry as EllipseGeometry;
point = new Point(ellipseGeometry.Center.X - formattedText.Width / 2,
ellipseGeometry.Center.Y - formattedText.Height / 2);
}
else if (ActualRatio == 0)
{
TextedGeometry = null;
return;
}
else
{
Point tangent;
Point half;
Point origin;
PathGeometry pathGeometry = Geometry as PathGeometry;
pathGeometry.GetPointAtFractionLength(.5, out half, out tangent);
pathGeometry.GetPointAtFractionLength(0, out origin, out tangent);
point = new Point(origin.X + ((half.X - origin.X) / 2) - formattedText.Width / 2,
origin.Y + ((half.Y - origin.Y) / 2) - formattedText.Height / 2);
}
combinedGeometry.Geometry1 = Geometry;
combinedGeometry.Geometry2 = formattedText.BuildGeometry(point);
TextedGeometry = combinedGeometry;
}
}
As you can see it adds a FormattedText
geometry (with the percentage) to the original Geometry
. Then you need to create a default style (in a generic.xaml dictionary) for using the new geometry property (named TextedGeometry
).
The style has to contain - at least - something like that:
<Path Name="Slice" Data="{TemplateBinding local:PieDataPoint.TextedGeometry}"
Fill="{TemplateBinding Control.Background}"
Stroke="{TemplateBinding Control.BorderBrush}"
StrokeMiterLimit="1">
<ToolTipService.ToolTip>
<StackPanel>
<ContentControl Content="{TemplateBinding chartingToolkit:DataPoint.FormattedDependentValue}" />
<ContentControl Content="{TemplateBinding chartingToolkit:PieDataPoint.FormattedRatio}" />
</StackPanel>
</ToolTipService.ToolTip>
</Path>
As you can see the "Slice" path has its Data
property binded to TextedGeometry
.
Now with a custom PieSeries
we can force the Chart
control to use our PieDataPoint
:
public class PieSeries : System.Windows.Controls.DataVisualization.Charting.PieSeries
{
protected override DataPoint CreateDataPoint()
{
return new PieDataPoint();
}
}
so in your XAML you can use:
<chartingToolkit:Chart Name="pieChart" Title="Pie Series Demo">
<local:PieSeries DependentValuePath="Value" IndependentValuePath="Key"
ItemsSource="{Binding}" IsSelectionEnabled="True" />
</chartingToolkit:Chart>
Where local
refers to your custom namespace. I hope it can help you.