Telerik blogs

It is pretty straight-forward to create a pie chart with a simple label that identifies the “category” for each slice. What is a bit trickier is to modify that label so that it shows not only the category, but the percentage each slice represents.

Let’s build the pie chart both ways to see the difference.

In either case, we begin with data. Our pie chart will reflect a municipal budget, and so our first class is BudgetData,

   1: public class BudgetData : INotifyPropertyChanged
   2: {
   3:     private double millions;
   4:     public double Millions
   5:     {
   6:         get { return millions; }
   7:         set
   8:         {
   9:             millions = value;
  10:             OnPropertyChanged();
  11:         }
  12:     }
  13:  
  14:     private string department;
  15:     public string Department
  16:     {
  17:         get { return department; }
  18:         set
  19:         {
  20:             department = value;
  21:             OnPropertyChanged();
  22:         }
  23:     }
  24:  
  25:     protected virtual void OnPropertyChanged( [CallerMemberName] string caller = "" )
  26:     {
  27:         if ( PropertyChanged != null )
  28:         {
  29:             PropertyChanged( this, new PropertyChangedEventArgs( caller ) );
  30:         }
  31:     }
  32:     public event PropertyChangedEventHandler PropertyChanged;
  33: }

Notice that we declare both the value of each pie slice in the property Millions (starting on line 4) as well as the category for each pie slice in the property Department (line 15).

Our second class is the main view model,

class MainVM
{
    public ObservableCollection<BudgetData> Data { get; private set; }
 
    public ChartPalette DefaultLightPalette
    {
        get { return ChartPalettes.DefaultLight; }
    }
 
    public MainVM()
    {
        PopulateData();
    }
 
    private void PopulateData()
    {
        Data = new ObservableCollection<BudgetData>();
        Data.Add( new BudgetData() { Millions = 43, Department = "Education" } );
        Data.Add( new BudgetData() { Millions = 27, Department = "Roads" } );
        Data.Add( new BudgetData() { Millions = 16, Department = "Social Programs" } );
        Data.Add( new BudgetData() { Millions = 13, Department = "Biz Incent" } );
        Data.Add( new BudgetData() { Millions = 12, Department = "Town Personnel" } );
        Data.Add( new BudgetData() { Millions = 5, Department = "Planning" } );
 
    }
}

The principal job of this class is to have a public property that our pie chart will bind to (Data). This class also generates dummy data to stand in for a database or other server.

In MainPage.xaml we create a static resource to point to the VM so that we can bind to it in XAML,

<Page.Resources>
 <local:MainVM x:Key="ViewModel"> 
 </local:MainVM>
</Page.Resources>

We set that ViewModel as the DataContext for the Grid (and thus all the controls within the Grid) by using the StaticResource we just created,

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"
 DataContext="{StaticResource ViewModel}">

We’re ready to create the PieChart. The first attribute is the PieSeries whose ItemsSource is bound to the Data collection in the VM,

<telerik:RadPieChart Palette="{Binding DefaultLightPalette}">
 <telerik:PieSeries
 ItemsSource="{Binding Data}"
 RadiusFactor="0.75">

Notice that we set the Palette by binding to a value in the ViewModel.  In the early beta this was required, but you can now just set it to a string.  Thus, you can remove the Palette from the ViewModel and here you can write

<telerik:RadPieChart Palette="DefaultLight" >

Continuing on, we next set the ValueBinding which will be bound to the Millions property in our BudgetData,

<telerik:PieSeries.ValueBinding>
 <telerik:PropertyNameDataPointBinding PropertyName="Millions" />
</telerik:PieSeries.ValueBinding>

Now comes the part that we will vary later in this blog post: the labelDefinitions.  In this first iteration, we will simply set the label to bind to the Department, doing all the work in the XAML,

<telerik:PieSeries.LabelDefinitions>
 <telerik:ChartSeriesLabelDefinition Margin="-20">
 <telerik:ChartSeriesLabelDefinition.Binding>
 <telerik:PropertyNameDataPointBinding
 PropertyName="Department" />
 </telerik:ChartSeriesLabelDefinition.Binding>
 </telerik:ChartSeriesLabelDefinition>
</telerik:PieSeries.LabelDefinitions>

Aside from closing the opening braces, that concludes the XAML. 

The result is a perfectly serviceable pie chart,

 StandardPieChart

Adding Percentages To The Label

If you wish to have both the Department and the percentage of the budget displayed in the label, then you must override methods in a class deriving from ChartSeriesLabelStrategy.  We’ll call ours PieLabelStrategy, and begin by setting a constant for the string format and a public property Binding,

public class PieLabelStrategy : ChartSeriesLabelStrategy
{
    private string format = "{0}\n{1:P2}";
 
    public PropertyNameDataPointBinding Binding { get; set; }

We override the Options property,

public override LabelStrategyOptions Options
{
    get { return LabelStrategyOptions.Content | LabelStrategyOptions.DefaultVisual; }
}

Next we override both CreateDefaultVisual as well as GetLabelContent,

public override FrameworkElement CreateDefaultVisual( DataPoint point, int labelIndex )
{
    ChartSeries series = point.Presenter as ChartSeries;
    return new TextBlock() 
    { 
        Foreground = series.Chart.Palette.GetBrush( 
        point.CollectionIndex, PaletteVisualPart.Fill ) 
    };
}
 
public override object GetLabelContent( DataPoint point, int labelIndex )
{
    if ( point == null || labelIndex < 0 )
    {
        return base.GetLabelContent( point, labelIndex );
    }
 
    return string.Format( 
        this.format, 
        Binding.GetValue( point.DataItem ), ( ( PieDataPoint )point ).Percent / 100 );
}

With this class ready to go, we return to MainPage.xaml and add to the resources section our PieLabelStrategy object,

<local:PieLabelStrategy x:Key="Strategy">
 <local:PieLabelStrategy.Binding>
 <telerik:PropertyNameDataPointBinding PropertyName="Department" />
 </local:PieLabelStrategy.Binding>
</local:PieLabelStrategy>

 

Finally, we remove the LabelDefinitions section, and replace it with a call into the new StaticResource we just created.

<telerik:PieSeries.LabelDefinitions>
 <telerik:ChartSeriesLabelDefinition Margin="-15"
 Strategy="{StaticResource Strategy}" />
</telerik:PieSeries.LabelDefinitions>

The result is the same pie chart but with the enhanced labeling,

EnhancedPieChart


jesseLiberty
About the Author

Jesse Liberty

 has three decades of experience writing and delivering software projects. He is the author of 2 dozen books and has been a Distinguished Software Engineer for AT&T and a VP for Information Services for Citibank and a Software Architect for PBS. You can read more on his personal blog or follow him on twitter

Comments

Comments are disabled in preview mode.