Articles in this section
Category / Section

How to generate series based on common items source?

5 mins read

Description:

This article describes how to generate dynamic number of series by binding a collection (items source) directly to chart.

Solution:

The solution for achieving this scenario is quite easy. It can be achieved by extending the SfChart (inheriting SfChart), and providing it with the SeriesTemplate (for customizing series type and its properties) and Source properties.

The implementation process is explained in the following steps:

Step 1: Define chart’s view model setup.

This step describes how to define the chart’s collection (items source) through MVVM.

Model

C#

 
public class PriceData
{   
    public string Component { get; set; }
 
    public double Price { get; set; }
}
 

C#

 
public class AnnualPriceData
{
    public string Year { get; set; }
 
    public ObservableCollection<PriceData> PriceCollection { get; set; }
}
 

 

View Model

C#

public class ViewModel
    {
        public ObservableCollection<AnnualPriceData> AnnualPriceCollection { get; set; }
 
        public ViewModel()
        {
            AnnualPriceCollection = new ObservableCollection<AnnualPriceData>();
 
            AnnualPriceCollection.Add(new AnnualPriceData()
            {
                Year = "2012",
                PriceCollection = new ObservableCollection<PriceData>()
                {
                    new PriceData() {Component = "Hard Disk", Price = 80 },
                    new PriceData() {Component = "Scanner", Price = 140  },
                    new PriceData() {Component = "Monitor", Price = 150  },
                    new PriceData() {Component = "Printer", Price = 180  },
                }
            });
            
            AnnualPriceCollection.Add(new AnnualPriceData()
            {
                Year = "2013",
                PriceCollection = new ObservableCollection<PriceData>()
                {
                    new PriceData() {Component = "Hard Disk", Price = 87 },
                    new PriceData() {Component = "Scanner", Price = 157  },
                    new PriceData() {Component = "Monitor", Price = 155  },
                    new PriceData() {Component = "Printer", Price = 192  },
                }
            });
 
            AnnualPriceCollection.Add(new AnnualPriceData()
            {
                Year = "2014",
                PriceCollection = new ObservableCollection<PriceData>()
                {
                    new PriceData() {Component = "Hard Disk", Price = 95 },
                    new PriceData() {Component = "Scanner", Price = 150  },
                    new PriceData() {Component = "Monitor", Price = 163  },
                    new PriceData() {Component = "Printer", Price = 185  },
                }
            });
 
            AnnualPriceCollection.Add(new AnnualPriceData()
            {
                Year = "2015",
                PriceCollection = new ObservableCollection<PriceData>()
                {
                    new PriceData() {Component = "Hard Disk", Price = 113 },
                    new PriceData() {Component = "Scanner", Price = 165  },
                    new PriceData() {Component = "Monitor", Price = 175  },
                    new PriceData() {Component = "Printer", Price = 212  },
                }
            });
 
            AnnualPriceCollection.Add(new AnnualPriceData()
            {
                Year = "2016",
                PriceCollection = new ObservableCollection<PriceData>()
                {
                    new PriceData() {Component = "Hard Disk", Price = 123 },
                    new PriceData() {Component = "Scanner", Price = 169 },
                    new PriceData() {Component = "Monitor", Price = 184 },
                    new PriceData() {Component = "Printer", Price = 224 },
                }
            });
        }
    }

Step 2: Implement the SfChart extension.

To achieve this requirement, we must use custom SfChart, which inherits from SfChart, and defines the following two properties: Source and SeriesTemplate.

Source:

The Source property is used to bind the items source (collection of collections) to chart. The chart series will be generated per item in the collection.

C#

 
//Gets or sets the ItemsSource (collection of collections).
 
public static readonly DependencyProperty SourceProperty =
        DependencyProperty.Register("Source", typeof(object), typeof(SfChartExt), new                                             
        PropertyMetadata(null, OnSourceChanged));
 
public object Source
{
    get { return (object)GetValue(SourceProperty); }
    set { SetValue(SourceProperty, value); }
}
 

SeriesTemplate:

The SeriesTemplate property is used to define the type and visual appearance of chart series. This template is more flexible; it allows us to define any type of series and all its properties since the content of the template is series.

C#

 
//Gets or sets the template for the series to be generated.
 
public static readonly DependencyProperty SeriesTemplateProperty =
        DependencyProperty.Register("SeriesTemplate", typeof(DataTemplate),    
        typeof(SfChartExt), new PropertyMetadata(null, OnSeriesTemplateChanged));
 
public DataTemplate SeriesTemplate
{
    get { return (DataTemplate)GetValue(SeriesTemplateProperty); }
    set { SetValue(SeriesTemplateProperty, value); }
}
 

The following code illustrates generating dynamic number of series based on data (collection).

C#

 
public class SfChartExt :  SfChart
{
 
public static readonly DependencyProperty SourceProperty =
DependencyProperty.Register("Source", typeof(object), typeof(SfChartExt), new PropertyMetadata(null, OnPropertyChanged));
        
public static readonly DependencyProperty SeriesTemplateProperty =
DependencyProperty.Register("SeriesTemplate", typeof(DataTemplate), typeof(SfChartExt), new PropertyMetadata(null, OnPropertyChanged));
        
//Gets or sets the ItemsSource of collection of collections.
 
public object Source
{
  get { return (object)GetValue(SourceProperty); }
  set { SetValue(SourceProperty, value); }
}
 
//Gets or sets the template for the series to be generated.
 
public DataTemplate SeriesTemplate
{
   get { return (DataTemplate)GetValue(SeriesTemplateProperty); }
   set { SetValue(SeriesTemplateProperty, value); }
}
 
private static void OnPropertyChanged(DependencyObject d,                              DependencyPropertyChangedEventArgs e)     
{
  (d as SfChartExt).GenerateSeries();
}
 
//Generate the series per the counts in the itemssource.
private void GenerateSeries()
{
    if (Source == null || SeriesTemplate == null) 
        return;                
            
    var commonItemsSource = (Source as IEnumerable).GetEnumerator();
 
    while(commonItemsSource.MoveNext())
    {
         ChartSeries series = SeriesTemplate.LoadContent() as ChartSeries;
         series.DataContext = commonItemsSource.Current;
         Series.Add(series);
    }   
 }
}
 

XAML

<local:SfChartExt Source="{Binding AnnualPriceCollection}" >
 
<--The SeriesTemplate is defined for generating the series.-->
    <local:SfChartExt.SeriesTemplate>
          <DataTemplate>
               <chart:ColumnSeries XBindingPath="Component"     
                                                    YBindingPath="Price"     
                                                    ItemsSource="{Binding PriceCollection}"
                                                    Label="{Binding Year}"/>
          </DataTemplate>
    </local:SfChartExt.SeriesTemplate>
 
<--Define required chart properties.-->
 
</local:SfChartExt>
 

The following column chart illustrates the result of above code.

Output:

Collection of series generated for the chart by single item source in UWP

To generate different types of chart series

We can generate multiple types of series by using the DataTemplateSelector property. A new class of SeriesDataTemplateSelector can be created by inheriting the DataTemplateSelector property.

C#

public class SeriesDataTemplateSelector : DataTemplateSelector
{
   public DataTemplate ColumnSeriesTemplate { get; set; }
   public DataTemplate LineSeriesTemplate { get; set; }
   public new DataTemplate SelectTemplate(object item)
   {
       //Check required conditions and return the selected template.
       
       DataTemplate selectedDataTemplate = null;
 
       string year = (item as AnnualPriceData).Year;
 
       if (year == "2015" || year =="2016")
           selectedDataTemplate = LineSeriesTemplate;
       else
           selectedDataTemplate = ColumnSeriesTemplate;
 
           return selectedDataTemplate;    
   }       
}
 

SfChart extension with SeriesTemplateSelector:

The SeriesTemplateSelector property is used to select the different series templates in single chart based on items.

C#

 
public class SfChartExt : SfChart
{
 
public static readonly DependencyProperty SeriesTemplateSelectorProperty =
DependencyProperty.Register("SeriesTemplateSelector", typeof(SeriesDataTemplateSelector), typeof(SfChartExt), new PropertyMetadata(null, OnPropertyChanged));
 
//Get or sets the DataTemplateSelector for the multiple series generation.
public SeriesDataTemplateSelector SeriesTemplateSelector
{
   get { return (SeriesDataTemplateSelector)GetValue(SeriesTemplateSelectorProperty); }
   set { SetValue(SeriesTemplateSelectorProperty, value); }
}  
 
//Generate the series according to the counts in the itemssource.
private void GenerateSeries()
{
    if (Source == null || (SeriesTemplateSelector == null && SeriesTemplate == null)) 
        return;     
     var commonItemsSource = (Source as IEnumerable).GetEnumerator();
 
     while(commonItemsSource.MoveNext())
     {
          ChartSeries series = null;
 
//The conditions checked for setting the SeriesTemplate or SeriesTemplateSelector.
          if (SeriesTemplate != null)
          {
              series = SeriesTemplate.LoadContent() as ChartSeries;
          }
          else if(SeriesTemplateSelector !=null)
          {
              var selectedseriesTemplate =   
              SeriesTemplateSelector.SelectTemplate(commonItemsSource.Current);     
              series = selectedseriesTemplate.LoadContent() as ChartSeries;
          }
 
          series.DataContext = commonItemsSource.Current;
          Series.Add(series);
                
            }
        }
}
 

SeriesDataTemplateSelector definition:

The different types of templates are defined in the resources for the SeriesTemplateSelector property.

XAML

<Grid.Resources>
 
    <DataTemplate x:Key="columnSeriesTemplate">
        <chart:ColumnSeries XBindingPath="Component" YBindingPath="Price" 
                                          ItemsSource="{Binding PriceCollection}"
                                          Label="{Binding Year}"/>
    </DataTemplate>
            
    <DataTemplate x:Key="lineSeriesTemplate" >
        <chart:LineSeries XBindingPath="Component" YBindingPath="Price" 
                                    ItemsSource="{Binding PriceCollection}"
                                    Label="{Binding Year}"/>
    </DataTemplate>
 
</Grid.Resources> 
 
<local:SfChartExt Source="{Binding AnnualPriceCollection}">
 
<!--The SeriesDataTemplateSelector is defined for generating the series.-->
            <local:SfChartExt.SeriesTemplateSelector>
                <local:SeriesDataTemplateSelector 
                                                  ColumnSeriesTemplate="{StaticResource
                                                  columnSeriesTemplate}"                    
                                                  LineSeriesTemplate="{StaticResource 
                                                  lineSeriesTemplate}" />
 
            </local:SfChartExt.SeriesTemplateSelector> 
 
</local:SfChartExt>
 
 

The following column and line series (multiple series) illustrates the result of above codes.

Output:

Collection of multiple types of series generated for the chart by single item source in UWP

Please find the required sample from this link.

Did you find this information helpful?
Yes
No
Help us improve this page
Please provide feedback or comments
Comments (0)
Please sign in to leave a comment
Access denied
Access denied