charley charley - 1 year ago 136
C# Question

"live chart" x axis not updating with along with time WPF c#

I have just started exploring the live chart library however can't seem to get the x axis to update as time passes. I have gone over this time and time again and can't seem to find the problem. The data points update correctly which is what I am finding so confusing!

I will at a later date be replacing the DateTime with a timer that displays how long the test has been running instead, if that makes the solution any simpler?

Part of me thinks this must be something simple I am missing!?

I appreciate any help on this one!

public partial class MainWindow : Window

private double _axisMax;
private double _axisMin;
Stopwatch stopwatch = new Stopwatch();

public MainWindow()
//To handle live data easily, in this case we built a specialized type
//the MeasureModel class, it only contains 2 properties
//DateTime and Value
//We need to configure LiveCharts to handle MeasureModel class
//The next code configures MEasureModel globally, this means
//that livecharts learns to plot MeasureModel and will use this config every time
//a ChartValues instance uses this type.
//this code ideally should only run once, when application starts is reccomended.
//you can configure series in many ways, learn more at

var mapper = Mappers.Xy<MeasureModel>()
.X(model => model.DateTime.Ticks) //use DateTime.Ticks as X
.Y(model => model.Value); //use the value property as Y

//lets save the mapper globally.

//the values property will store our values array
ChartValues = new ChartValues<MeasureModel>();

//lets set how to display the X Labels
DateTimeFormatter = value => new DateTime((long)value).ToString("hh:mm:ss");

AxisStep = TimeSpan.FromSeconds(1).Ticks;

//The next code simulates data changes every 300 ms
Timer = new DispatcherTimer
Interval = TimeSpan.FromMilliseconds(300)
Timer.Tick += TimerOnTick;
IsDataInjectionRunning = false;
R = new Random();
DataContext = this;

public ChartValues<MeasureModel> ChartValues { get; set; }
public Func<double, string> DateTimeFormatter { get; set; }

public double AxisStep { get; set; }

public double AxisMax
get { return _axisMax; }
_axisMax = value;
public double AxisMin
get { return _axisMin; }
_axisMin = value;

public DispatcherTimer Timer { get; set; }
public bool IsDataInjectionRunning { get; set; }
public Random R { get; set; }

private void RunDataOnClick(object sender, RoutedEventArgs e)
if (IsDataInjectionRunning)
IsDataInjectionRunning = false;
IsDataInjectionRunning = true;

private void TimerOnTick(object sender, EventArgs eventArgs) // Class is referencing from here!
var now = DateTime.Now;

ChartValues.Add(new MeasureModel
DateTime = DateTime.Now,
Value = R.Next(0, 10)


//lets only use the last 30 values
if (ChartValues.Count > 30) ChartValues.RemoveAt(0);

private void SetAxisLimits(DateTime now)
AxisMax = now.Ticks + TimeSpan.FromSeconds(20).Ticks; // lets force the axis to be 100ms ahead
AxisMin = now.Ticks - TimeSpan.FromSeconds(8).Ticks; //we only care about the last 8 seconds

public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged(string propertyName = null)
if (PropertyChanged != null) // if subrscribed to event
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));

public class MeasureModel
public DateTime DateTime { get; set; }
public double Value { get; set; }

xmlns:chart="" x:Class="graph_test_6.MainWindow"
Title="MainWindow" Height="350" Width="525">
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<Button Grid.Row="0" Height="30" Click="RunDataOnClick">
Inject/Stop Data
<lvc:CartesianChart Grid.Row="1">
<lvc:LineSeries Values="{Binding ChartValues}" PointGeometrySize="18" StrokeThickness="4" />
<lvc:Axis LabelFormatter="{Binding DateTimeFormatter}"
MaxValue="{Binding AxisMax}"
MinValue="{Binding AxisMin}"
<lvc:Separator Step="{Binding AxisStep}"></lvc:Separator>
<TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="323,-71,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>

Screen shot of problem

Answer Source

In Xaml you are binding for AxisX properties MaxValue and MinValue:

 MaxValue="{Binding AxisMax}" 
 MinValue="{Binding AxisMin}"

When window is loaded WPF mechanism reads the values that are bound: that's how you are getting initial values for X Axes. Later in code you are changing these values:

 AxisMax = now.Ticks + TimeSpan.FromSeconds(20).Ticks; // lets force the axis to be 100ms ahead
 AxisMin = now.Ticks - TimeSpan.FromSeconds(8).Ticks; //we only care about the last 8 seconds

Xaml should be notified about these changes and it's done via:


The problem is that window control itself doesn't declare, that it supports change notifications: it's missing INotifyPropertyChanged.

So to fix your issue change

public partial class MainWindow : Window


 public partial class MainWindow  : Window, INotifyPropertyChanged