How to Create Dynamic WPF Charts in .NET C# Apps
Visualizing data is a common need for users. Data can be visualized in different forms, like in a table/grid form or a graphical representation, for example. ComponentOne FlexGrid is used to visualize data in table/grid form, and FlexChart is a graphical representation of data. FlexGrid and FlexChart can be synchronously connected to the data to see dynamic updates on any change in data.
This blog will show how to connect a FlexChart to a FlexGrid to create a bound MVVM (Model-View-ViewModel) scenario similar to Microsoft Excel. Users can add, delete and modify items in FlexGrid, which will reflect in FlexChart.
Steps to Create a Dynamic WPF Chart
Create the Model and ViewModel
Create a model class according to the data and implement the INotifyPropertyChanged interface to notify when a property value changes. This is the key step so that when data changes by FlexGrid, the View (which also contains FlexChart) will be notified.
public class Country : INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; OnPropertyRaised("Name"); }
}
private int _sales;
public int Sales
{
get { return _sales; }
set { _sales = value; OnPropertyRaised("Sales"); }
}
private int _downloads;
public int Downloads
{
get { return _downloads; }
set { _downloads = value; OnPropertyRaised("Downloads"); }
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyRaised(string property)
{
if(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
Now, create a ViewModel named DataViewModel, which will connect to the View. We can create some properties and methods in ViewModel which can be bound to the view.
public class DataViewModel
{
private ObservableCollection<Country> _countries;
public ObservableCollection<Country> Countries
{
get { return _countries; }
set { _countries = value; }
}
private string _desc;
public string Desc
{
get { return _desc; }
set { _desc = value; }
}
/// <summary>
/// C'tor
/// </summary>
public DataViewModel()
{
//create a dummy data
var country = new string[] { "China", "India", "Japan", "US" };
var count = country.Length;
Countries = new ObservableCollection<Country>();
var rnd = new Random();
for (var i = 0; i < count; i++)
Countries.Add(new Country()
{
Name = country[i],
Sales = 1 + rnd.Next(100,1000),
Downloads = 1 + rnd.Next(100, 1000),
});
Desc = "You can modify, add or delete Flexgrid's item and this will reflect on FlexChart.";
}
}
Create the View
Now, it’s time to create a User Interface(View). Add C1FlexChart and C1FlexGrid to the view, bound their ItemsSources and respective properties.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DynamicFlexChart"
xmlns:c1="http://schemas.componentone.com/winfx/2006/xaml" x:Class="DynamicFlexChart.MainWindow"
xmlns:vm ="clr-namespace:DynamicFlexChart.ViewModel"
mc:Ignorable="d"
Title="Dynamic FlexChart" Height="450" Width="800">
<Window.DataContext>
<vm:DataViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock x:Name="desc" Text="{Binding Desc}" FontSize="14" TextWrapping="Wrap" Margin="10,0,0,0"/>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<!-- FlexGrid -->
<c1:C1FlexGrid x:Name="flexGrid" ItemsSource="{Binding Countries}" AllowAddNew="True" KeyDown="Key_Down" AutoGenerateColumns="False">
<c1:C1FlexGrid.Columns>
<c1:Column Header="Name" Binding="{Binding Name}"/>
<c1:Column Header="Sales" Binding="{Binding Sales}"/>
<c1:Column Header="Downloads" Binding="{Binding Downloads}"/>
</c1:C1FlexGrid.Columns>
</c1:C1FlexGrid>
<!-- FlexChart -->
<c1:C1FlexChart x:Name="flexChart" Grid.Column="1" ItemsSource="{Binding Countries}" BindingX="Name" LegendPosition="Bottom">
<c1:C1FlexChart.Series>
<c1:Series Binding="Sales" SeriesName="Sales"/>
<c1:Series Binding="Downloads" SeriesName="Downloads"/>
</c1:C1FlexChart.Series>
<c1:C1FlexChart.DataLabel>
<c1:DataLabel Content=" {value}" Position="Top"/>
</c1:C1FlexChart.DataLabel>
</c1:C1FlexChart>
</Grid>
</Grid>
</Window>
And it’s done. Now you can edit, add or remove data from Flexgrid, which will dynamically update to the FlexChart.
For full implementation, you can download the sample.
Originally published at https://www.developer.mescius.com on March 31, 2023.