Skip to main content
All docs
V25.1
  • 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;
            }
        }
    }