Skip to content

Commit 7543f50

Browse files
authored
Update README.md
1 parent a3259ff commit 7543f50

File tree

1 file changed

+285
-3
lines changed

1 file changed

+285
-3
lines changed

README.md

Lines changed: 285 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,287 @@
1-
# How to generate dynamic number of series based on items source in WPF Chart (SfChart)?
1+
# How to generate dynamic number of series based on common items source in WPF Chart (SfChart)?
22

3-
You can generate dynamic number of series by extending the [WPF Chart](https://www.syncfusion.com/wpf-controls/charts) (inheriting SfChart) and providing it with the SeriesTemplate (for customizing series type and its properties) and Source properties.
3+
This article describes how to generate dynamic number of series by binding a collection (Items source) directly to chart.
44

5-
KB article - [How to generate dynamic number of series based on items source in WPF Chart (SfChart)?](https://www.syncfusion.com/kb/7578/how-to-generate-dynamic-number-of-series-based-on-common-items-source-in-wpf-chart-sfchart)
5+
You can generate dynamic number of series by extending the WPF Chart (inheriting SfChart) and providing it with the SeriesTemplate (for customizing series type and its properties) and Source properties.
6+
7+
The implementation process is explained in the following steps.
8+
9+
**Step 1:** Define chart’s view model setup
10+
11+
This step describes how to define the chart’s collection (items source) through MVVM.
12+
13+
**Model**
14+
```
15+
public class PriceData
16+
{  
17+
    public string Component { get; set; }
18+
    public double Price { get; set; }
19+
}
20+
```
21+
```
22+
public class AnnualPriceData
23+
{
24+
    public string Year { get; set; }
25+
    public ObservableCollection<PriceData> PriceCollection { get; set; }
26+
}
27+
```
28+
29+
**View Model**
30+
```
31+
public class ViewModel
32+
{
33+
  public ObservableCollection<AnnualPriceData> AnnualPriceCollection { get; set; }
34+
  public ViewModel()
35+
  {
36+
    AnnualPriceCollection = new ObservableCollection<AnnualPriceData>();
37+
    AnnualPriceCollection.Add(new AnnualPriceData()
38+
    {
39+
      Year = "2012",
40+
      PriceCollection = new ObservableCollection<PriceData>()
41+
      {
42+
        new PriceData() {Component = "Hard Disk", Price = 80 },
43+
        new PriceData() {Component = "Scanner", Price = 140  },
44+
        new PriceData() {Component = "Monitor", Price = 150  },
45+
        new PriceData() {Component = "Printer", Price = 180  },
46+
      }
47+
    });
48+
           
49+
    AnnualPriceCollection.Add(new AnnualPriceData()
50+
    {
51+
      Year = "2013",
52+
      PriceCollection = new ObservableCollection<PriceData>()
53+
      {
54+
        new PriceData() {Component = "Hard Disk", Price = 87 },
55+
        new PriceData() {Component = "Scanner", Price = 157  },
56+
        new PriceData() {Component = "Monitor", Price = 155  },
57+
        new PriceData() {Component = "Printer", Price = 192  },
58+
      }
59+
    });
60+
 
61+
    AnnualPriceCollection.Add(new AnnualPriceData()
62+
    {
63+
      Year = "2014",
64+
      PriceCollection = new ObservableCollection<PriceData>()
65+
      {
66+
        new PriceData() {Component = "Hard Disk", Price = 95 },
67+
        new PriceData() {Component = "Scanner", Price = 150  },
68+
        new PriceData() {Component = "Monitor", Price = 163  },
69+
        new PriceData() {Component = "Printer", Price = 185  },
70+
      }
71+
    });
72+
 
73+
    AnnualPriceCollection.Add(new AnnualPriceData()
74+
    {
75+
      Year = "2015",
76+
      PriceCollection = new ObservableCollection<PriceData>()
77+
      {
78+
        new PriceData() {Component = "Hard Disk", Price = 113 },
79+
        new PriceData() {Component = "Scanner", Price = 165  },
80+
        new PriceData() {Component = "Monitor", Price = 175  },
81+
        new PriceData() {Component = "Printer", Price = 212  },
82+
      }
83+
    });
84+
 
85+
    AnnualPriceCollection.Add(new AnnualPriceData()
86+
    {
87+
      Year = "2016",
88+
      PriceCollection = new ObservableCollection<PriceData>()
89+
      {
90+
        new PriceData() {Component = "Hard Disk", Price = 123 },
91+
        new PriceData() {Component = "Scanner", Price = 169 },
92+
        new PriceData() {Component = "Monitor", Price = 184 },
93+
        new PriceData() {Component = "Printer", Price = 224 },
94+
      }
95+
    });
96+
  }
97+
}
98+
```
99+
100+
**Step 2:** Implement SfChart extension
101+
102+
To achieve this requirement, use the custom [WPF Chart (SfChart)](https://help.syncfusion.com/wpf/charts/getting-started), which inherits from SfChart and defines two properties, namely the **Source** and **SeriesTemplate** properties.
103+
104+
**Source:**
105+
106+
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.
107+
```
108+
//Gets or sets the ItemsSource (collection of collections).
109+
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(object), typeof(SfChartExt), new PropertyMetadata(null, OnSourceChanged));
110+
 
111+
public object Source
112+
{
113+
  get { return (object)GetValue(SourceProperty); }
114+
  set { SetValue(SourceProperty, value); }
115+
}
116+
```
117+
**SeriesTemplate:**
118+
119+
The **SeriesTemplate** property is used to define the type and visual appearance of chart series. This template is more flexible, and it allows you to define any type of series and all its properties since the content of the template is the series.
120+
121+
```
122+
//Gets or sets the template for the series to be generated.
123+
public static readonly DependencyProperty SeriesTemplateProperty = DependencyProperty.Register("SeriesTemplate", typeof(DataTemplate), typeof(SfChartExt), new PropertyMetadata(null, OnSeriesTemplateChanged));
124+
 
125+
public DataTemplate SeriesTemplate
126+
{
127+
  get { return (DataTemplate)GetValue(SeriesTemplateProperty); }
128+
  set { SetValue(SeriesTemplateProperty, value); }
129+
}
130+
```
131+
132+
The following code illustrates generating dynamic number of series based on data(collection).
133+
```
134+
public class SfChartExt :  SfChart
135+
{
136+
  public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(object), typeof(SfChartExt), new PropertyMetadata(null, OnPropertyChanged));
137+
  public static readonly DependencyProperty SeriesTemplateProperty = DependencyProperty.Register("SeriesTemplate", typeof(DataTemplate), typeof(SfChartExt), new PropertyMetadata(null, OnPropertyChanged));
138+
 
139+
  //Gets or sets the ItemsSource of collection of collections.
140+
  public object Source
141+
  {
142+
    get { return (object)GetValue(SourceProperty); }
143+
    set { SetValue(SourceProperty, value); }
144+
  }
145+
  //Gets or sets the template for the series to be generated.
146+
  public DataTemplate SeriesTemplate
147+
  {
148+
    get { return (DataTemplate)GetValue(SeriesTemplateProperty); }
149+
    set { SetValue(SeriesTemplateProperty, value); }
150+
  }
151+
  private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)    
152+
  {
153+
    (d as SfChartExt).GenerateSeries();
154+
  }
155+
  //Generate the series per the counts in the itemssource.
156+
  private void GenerateSeries()
157+
  {
158+
    if (Source == null || SeriesTemplate == null)
159+
      return;               
160+
    var commonItemsSource = (Source as IEnumerable).GetEnumerator();
161+
    while(commonItemsSource.MoveNext())
162+
    {
163+
       ChartSeries series = SeriesTemplate.LoadContent() as ChartSeries;
164+
       series.DataContext = commonItemsSource.Current;
165+
       Series.Add(series);
166+
    }  
167+
  }
168+
}
169+
```
170+
171+
```
172+
<local:SfChartExt Source="{Binding AnnualPriceCollection}" >
173+
<--The SeriesTemplate is defined for generating the series.-->
174+
    <local:SfChartExt.SeriesTemplate>
175+
          <DataTemplate>
176+
               <chart:ColumnSeries XBindingPath="Component"    
177+
                                                    YBindingPath="Price"    
178+
                                                    ItemsSource="{Binding PriceCollection}"
179+
                                                    Label="{Binding Year}"/>
180+
          </DataTemplate>
181+
    </local:SfChartExt.SeriesTemplate>
182+
<--Define required chart properties.-->
183+
</local:SfChartExt>
184+
```
185+
186+
The following illustrates the result of above code examples.
187+
188+
![image](https://user-images.githubusercontent.com/53489303/200557020-101820b2-580b-4120-81d2-9cbb32133b63.png)
189+
190+
**To generate different types of chart series**
191+
192+
You can generate multiple types of series by using the **DataTemplateSelector** property. A new class of **SeriesDataTemplateSelector** can be created by inheriting the DataTemplateSelector to achieve this requirement.
193+
194+
```
195+
public class SeriesDataTemplateSelector : DataTemplateSelector
196+
{
197+
   public DataTemplate ColumnSeriesTemplate { get; set; }
198+
   public DataTemplate LineSeriesTemplate { get; set; }
199+
   public override DataTemplate SelectTemplate(object item, DependencyObject container)
200+
   {
201+
       //Check required conditions and return the selected template.
202+
       DataTemplate selectedDataTemplate = null;
203+
       string year = (item as AnnualPriceData).Year;
204+
       if (year == "2015" || year =="2016")
205+
         selectedDataTemplate = LineSeriesTemplate;
206+
       else
207+
         selectedDataTemplate = ColumnSeriesTemplate;
208+
       return selectedDataTemplate;   
209+
   }      
210+
}
211+
```
212+
213+
**SfChart extension with SeriesTemplateSelector:**
214+
215+
The **SeriesTemplateSelector** property is used to select the different series template in single chart based on item.
216+
```
217+
public class SfChartExt : SfChart
218+
{
219+
  public static readonly DependencyProperty SeriesTemplateSelectorProperty = DependencyProperty.Register("SeriesTemplateSelector", typeof(SeriesDataTemplateSelector), typeof(SfChartExt), new PropertyMetadata(null, OnPropertyChanged));
220+
 
221+
  //Get or sets the DataTemplateSelector for the multiple series generation.
222+
  public SeriesDataTemplateSelector SeriesTemplateSelector
223+
  {
224+
   get { return (SeriesDataTemplateSelector)GetValue(SeriesTemplateSelectorProperty);}
225+
   set { SetValue(SeriesTemplateSelectorProperty, value); }
226+
  } 
227+
 
228+
  //Generate the series according to the counts in the itemssource.
229+
  private void GenerateSeries()
230+
  {
231+
    if (Source == null || (SeriesTemplateSelector == null && SeriesTemplate == null))
232+
      return;    
233+
    var commonItemsSource = (Source as IEnumerable).GetEnumerator();
234+
    while(commonItemsSource.MoveNext())
235+
    {
236+
       ChartSeries series = null;
237+
       //The conditions checked for setting the SeriesTemplate or SeriesTemplateSelector.
238+
       if (SeriesTemplate != null)
239+
       {
240+
          series = SeriesTemplate.LoadContent() as ChartSeries;
241+
       }
242+
       else if(SeriesTemplateSelector !=null)
243+
       {
244+
          var selectedseriesTemplate = SeriesTemplateSelector.SelectTemplate(commonItemsSource.Current, null);    
245+
          series = selectedseriesTemplate.LoadContent() as ChartSeries;
246+
       }
247+
       series.DataContext = commonItemsSource.Current;
248+
       Series.Add(series);
249+
    }
250+
  }
251+
}
252+
```
253+
254+
**SeriesDataTemplateSelector definition:**
255+
256+
The different types of templates are defined in the resources for the **SeriesTemplateSelector** property.
257+
```
258+
<Grid.Resources>
259+
    <DataTemplate x:Key="columnSeriesTemplate">
260+
        <chart:ColumnSeries XBindingPath="Component" YBindingPath="Price"
261+
                                          ItemsSource="{Binding PriceCollection}"
262+
                                          Label="{Binding Year}"/>
263+
    </DataTemplate>
264+
    <DataTemplate x:Key="lineSeriesTemplate" >
265+
        <chart:LineSeries XBindingPath="Component" YBindingPath="Price"
266+
                                    ItemsSource="{Binding PriceCollection}"
267+
                                    Label="{Binding Year}"/>
268+
    </DataTemplate>
269+
</Grid.Resources>
270+
 
271+
<local:SfChartExt Source="{Binding AnnualPriceCollection}">
272+
     <!--The SeriesDataTemplateSelector is defined for generating the series.-->
273+
     <local:SfChartExt.SeriesTemplateSelector>
274+
                <local:SeriesDataTemplateSelector
275+
                                                  ColumnSeriesTemplate="{StaticResource
276+
                                                  columnSeriesTemplate}"                   
277+
                                                 LineSeriesTemplate="{StaticResource
278+
                                                  lineSeriesTemplate}" />
279+
     </local:SfChartExt.SeriesTemplateSelector>
280+
</local:SfChartExt>
281+
```
282+
283+
The following column and line series (multiple series) are created as the result of above code examples.
284+
285+
![image](https://user-images.githubusercontent.com/53489303/200557340-1f010c57-0245-4cb4-b99f-871876ceb2bc.png)
286+
287+
KB article - [How to generate dynamic number of series based on common items source in WPF Chart (SfChart)?](https://www.syncfusion.com/kb/7578/how-to-generate-dynamic-number-of-series-based-on-common-items-source-in-wpf-chart-sfchart)

0 commit comments

Comments
 (0)