Create Data-Bound Chart

RadChartView supports data binding and manual population with data out of the box. The data binding feature is exposed by the different series and can be utilized by assigning a value to the ItemsSource property of a series object. Each series has a collection of data points, that is, a data source which it displays according to the series type. For more information on chart series, please refer to our Chart Series topic. ItemsSource is of type IEnumerable and can therefore be bound to anything. If the data source is a collection of custom objects, users will have to provide a ValueBinding which will be used by the series to determine to which property the data points of the chart will be bound to.

If the data source consists of primitive numeric types (byte, short, int, float , double, decimal) the objects in the data source will be used directly as values for the data points. Here are two examples of how to bind RadChartView to a data source of primitive types and to a data source of custom objects.

The following examples will demonstrate how to bind the BarSeries of the chart.

The DataPoints collection property of the series will be populated when their ItemsSource is used.

Binding in XAML

The series in a chart can be bound through XAML assuming the DataContext of our series is the data source. First we are going to create a ViewModel class which will hold our collection of Product. We will use the Product class define in the Example 1.

Example 1: Creating ViewModel class

public class Product 
{ 
    public string Name { get; set; } 
    public int QuantitySold { get; set; } 
} 
public class ViewModel 
{ 
    public ObservableCollection<Product> Data { get; set; } 
    Random rnd = new Random(); 
    public ViewModel() 
    { 
        Data = new ObservableCollection<Product>(); 
        GetData(); 
    } 
    private void GetData() 
    { 
        for (int i = 0; i < 10; i++) 
        { 
            Product product = new Product(); 
            product.Name = "Product " + i; 
            product.QuantitySold = rnd.Next(10,99) ; 
            Data.Add(product); 
        } 
    } 
} 
Public Class ViewModel 
    Public Property Data As ObservableCollection(Of Product) 
    Private rnd As Random = New Random() 
    Public Sub New() 
        Data = New ObservableCollection(Of Product)() 
        GetData() 
    End Sub 
    Private Sub GetData() 
        For i As Integer = 0 To 10 - 1 
            Dim product As Product = New Product() 
            product.Name = "Product " & i 
            product.QuantitySold = rnd.Next 
            Data.Add(product) 
        Next 
    End Sub 
End Class 

The next step is to set the DataContext of the MainWindow to our ViewModel class.

Example 2: Specifying DataContext of the MainWindow

public MainWindow() 
{ 
    InitializeComponent(); 
    this.DataContext = new ViewModel(); 
} 
Public Sub New() 
    InitializeComponent() 
    Me.DataContext = New ViewModel() 
End Sub 

Example 3: Binding BarSeries in XAML

<telerik:RadCartesianChart x:Name="chart"> 
 
    <telerik:RadCartesianChart.HorizontalAxis> 
        <telerik:CategoricalAxis/> 
    </telerik:RadCartesianChart.HorizontalAxis> 
 
    <telerik:RadCartesianChart.VerticalAxis> 
        <telerik:LinearAxis/> 
    </telerik:RadCartesianChart.VerticalAxis> 
 
    <telerik:RadCartesianChart.Series> 
        <telerik:BarSeries x:Name="barSeries" CategoryBinding="Name" ValueBinding="QuantitySold" ItemsSource="{Binding Data}"/> 
    </telerik:RadCartesianChart.Series> 
</telerik:RadCartesianChart> 

Figure 1: Binding BarSeries in XAML

Binding BarSeries in XAML

Binding BarSeries to primitive types

For any series object the data source can be set to an enumerable of primitive numerical types. In this case the data points' values will the values in the enumerable themselves. For example for any series object the following code binds it:

Example 3: Binding BarSeries in XAML

<telerik:RadCartesianChart x:Name="chart"> 
 
    <telerik:RadCartesianChart.HorizontalAxis> 
        <telerik:CategoricalAxis/> 
    </telerik:RadCartesianChart.HorizontalAxis> 
 
    <telerik:RadCartesianChart.VerticalAxis> 
        <telerik:LinearAxis/> 
    </telerik:RadCartesianChart.VerticalAxis> 
 
    <telerik:RadCartesianChart.Series> 
        <telerik:BarSeries x:Name="barSeries" /> 
    </telerik:RadCartesianChart.Series> 
</telerik:RadCartesianChart> 

Example 4: Binding BarSeries to primitive types

public MainWindow() 
{ 
    InitializeComponent(); 
    barSeries.ItemsSource = new double[] { 20, 30, 50, 10, 60, 40, 20, 80 }; 
} 
Public Sub New() 
    InitializeComponent() 
    barSeries.ItemsSource = New Double() { 20, 30, 50, 10, 60, 40, 20, 80 } 
End Sub  

Figure 2: Binding BarSeries to primitive types

Binding BarSeries to primitive types

Binding BarSeries in code behind

Let's assume that we need to visualize how many products of certain types are sold for the last month. First we will create a product class and then we can bind a bar series to a collection of our products.

Example 5: Creating Product class

public class Product 
{ 
    public string Name 
    { 
        get; 
        set; 
    } 
    public double QuantitySold 
    { 
        get; 
        set; 
    } 
} 
Public Class Product 
    Private _name As String 
    Private _quantitySold As Double 
 
    Public Property Name As String 
        Get 
            Return Me._name 
        End Get 
        Set(value As String) 
            Me._name = value 
        End Set 
    End Property 
    Public Property QuantitySold As Double 
        Get 
            Return Me._quantitySold 
        End Get 
        Set(value As Double) 
            Me._quantitySold = value 
        End Set 
    End Property 
End Class 

Example 6: Binding BarSeries in code behind

List<Product> dataSource = new List<Product>(); 
dataSource.Add(new Product() { Name = "Product 1", QuantitySold = 5  }); 
dataSource.Add(new Product() { Name = "Product 2", QuantitySold = 50  }); 
dataSource.Add(new Product() { Name = "Product 3", QuantitySold = 8 }); 
barSeries.CategoryBinding = new PropertyNameDataPointBinding() { PropertyName = "Name" }; 
barSeries.ValueBinding = new GenericDataPointBinding<Product, double>() { ValueSelector = product => product.QuantitySold }; 
barSeries.ItemsSource = dataSource; 
Dim dataSource As List(Of Product) = New List(Of Product)() 
Dim nameBinding As PropertyNameDataPointBinding = New PropertyNameDataPointBinding 
nameBinding.PropertyName = "Name" 
Dim genericBinding As GenericDataPointBinding(Of Product, Double) = New GenericDataPointBinding(Of Product, Double) 
genericBinding.ValueSelector = Function(product) product.QuantitySold 
barSeries.CategoryBinding = nameBinding 
barSeries.ValueBinding = genericBinding 
barSeries.ItemsSource = dataSource 

The two binding classes, ValueBinding and CategoryBinding are set so that the series knows which property to bind to the value of a data point and which property to bind to the category of a data point. RadChart supports two types of binding objects out of the box and these are PropertyNameDataPointBinding and GenericDataPointBinding. The two binding classes do the same thing but they have different performance characteristics. PropertyNameDataPointBinding uses reflection internally to lookup values which can be slow and is not recommended for real-time charts where the items in the data source are updated frequently. For static charts it is preferred because they are very easy to use. Also if binding is done through XAML, the PropertyNameDataPointBinding is the only approach. GenericDataPointBinding on the other hand has to be setup through code and is a lot faster because the user typically knows which property needs to be bound to the category or the value of the data points and can do the binding with a simple variable assignment, avoiding the slower reflection based approach.

If a series is bound to an observable collection, the series will update as soon as a property of a data item changes. If we needed to track the selling of our products in real-time, we can simply put the product types in an observable collection and whenever we update a product's sold quantity, the chart will be updated. For example:

Example 7: Binding BarSeries to ObservableCollection

ObservableCollection<Product> products = new ObservableCollection<Product>(); 
// fill collection 
barSeries.CategoryBinding = new PropertyNameDataPointBinding() { PropertyName = "Name" }; 
barSeries.ValueBinding = new GenericDataPointBinding<Product, double>() { ValueSelector = product => product.QuantitySold }; 
barSeries.ItemsSource = products; 
Dim products As ObservableCollection(Of Product) = New ObservableCollection(Of Product) 
' fill collection ' 
Dim nameBinding As PropertyNameDataPointBinding = New PropertyNameDataPointBinding 
nameBinding.PropertyName = "Name" 
Dim genericBinding As GenericDataPointBinding(Of Product, Double) = New GenericDataPointBinding(Of Product, Double) 
genericBinding.ValueSelector = Function(product) product.QuantitySold 
barSeries.CategoryBinding = nameBinding 
barSeries.ValueBinding = genericBinding 
barSeries.ItemsSource = dataSource 

The only requirement left for the code above to work is that our Product class needs to implement INotifyPropertyChanged and raise the PropertyChanged event when its QuantitySold property changes. In Example 8 we will inherit ViewModelBase class which implement INotifyPropertyChanged interface.

Example 8: Creating Product class

public class Product : ViewModelBase 
{ 
    public string Name { get; set; } 
    private int _quantitySold; 
 
    public int QuantitySold 
    { 
        get { return _quantitySold; } 
        set {  
            _quantitySold = value;  
            this.OnPropertyChanged("QuantitySold");  
        } 
    } 
} 

See Also

In this article