How to: Create a Real-Time Chart (MVVM)
- 3 minutes to read
The following example creates a chart and updates its data source in real time.
The example uses an ObservableCollection as the data source for a series. ObservableCollection notifies the chart about new items and the chart is rendered again.
<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:RealtimeChartMvvm"
xmlns:dxc="http://schemas.devexpress.com/winfx/2008/xaml/charts"
x:Class="RealtimeChartMvvm.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<dxc:ChartControl x:Name="chart" BoundDataChanged="chart_BoundDataChanged">
<dxc:ChartControl.DataContext>
<local:ChartViewModel/>
</dxc:ChartControl.DataContext>
<dxc:XYDiagram2D x:Name="diagram"
DependentAxesYRange="True">
<dxc:SplineSeries2D DisplayName="Series 1"
DataSource="{Binding DataPoints}"
ArgumentDataMember="Argument"
ValueDataMember="Value" >
<dxc:SplineSeries2D.LastPoint>
<dxc:SidePoint LabelDisplayMode="SeriesPoint">
<dxc:SidePoint.Label>
<dxc:SeriesLabel TextPattern="{}{V:f2}"/>
</dxc:SidePoint.Label>
</dxc:SidePoint>
</dxc:SplineSeries2D.LastPoint>
</dxc:SplineSeries2D>
<dxc:XYDiagram2D.AxisX>
<dxc:AxisX2D>
<dxc:AxisX2D.DateTimeScaleOptions>
<dxc:ContinuousDateTimeScaleOptions/>
</dxc:AxisX2D.DateTimeScaleOptions>
</dxc:AxisX2D>
</dxc:XYDiagram2D.AxisX>
<dxc:XYDiagram2D.AxisY>
<dxc:AxisY2D>
<dxc:AxisY2D.WholeRange>
<dxc:Range dxc:AxisY2D.AlwaysShowZeroLevel="False"/>
</dxc:AxisY2D.WholeRange>
</dxc:AxisY2D>
</dxc:XYDiagram2D.AxisY>
</dxc:XYDiagram2D>
</dxc:ChartControl>
</Grid>
</Window>
Code-Behind:
using DevExpress.Xpf.Charts;
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Threading;
namespace RealtimeChartMVVM {
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void chart_BoundDataChanged(object sender, RoutedEventArgs e) {
// Adjust the visual range.
AxisX2D axisX = ((XYDiagram2D)chart.Diagram).ActualAxisX;
DateTime maxRangeValue = (DateTime)axisX.ActualWholeRange.ActualMaxValue;
axisX.ActualVisualRange.SetMinMaxValues(maxRangeValue.AddSeconds(-10), maxRangeValue);
}
}
public class ChartViewModel {
const int MaxPointCount = 3000;
readonly DispatcherTimer timer = new DispatcherTimer();
public ObservableCollection<DataPoint> DataPoints { get; } = new ObservableCollection<DataPoint>();
public ChartViewModel() {
timer.Tick += Timer_Tick;
timer.Interval = TimeSpan.FromMilliseconds(100);
timer.Start();
}
private void Timer_Tick(object sender, System.EventArgs e) {
this.DataPoints.Add(new DataPoint(DateTime.Now, GenerateValue(DataPoints.Count)));
if (DataPoints.Count == MaxPointCount) { timer.Stop(); }
}
private double GenerateValue(double x) {
return Math.Sin(x) * 3 + x / 2 + 5;
}
}
public class DataPoint {
public DateTime Argument { get; set; }
public double Value { get; set; }
public DataPoint(DateTime argument, double value) {
this.Argument = argument;
this.Value = value;
}
}
}