Skip to main content

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.

View Example

<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;
        }
    }
}