Automatic Updates
This example uses the LineSeries
class but it works the same for any series in the library
View model
using System;
using System.Collections.ObjectModel;
using System.Linq;
using CommunityToolkit.Mvvm.Input;
using LiveChartsCore;
using LiveChartsCore.Defaults;
using LiveChartsCore.SkiaSharpView;
namespace ViewModelsSamples.Lines.AutoUpdate;
public partial class ViewModel
{
private readonly Random _random = new();
// We use the ObservableCollection class to let the chart know // mark
// when a new item is added or removed from the chart. // mark
public ObservableCollection<ISeries> Series { get; set; }
// The ObservablePoints property is an ObservableCollection of ObservableValue // mark
// it means that the chart is listening for changes in this collection // mark
// and also for changes in the properties of each element in the collection // mark
public ObservableCollection<ObservableValue> ObservableValues { get; set; }
public ViewModel()
{
ObservableValues = [
new() { Value = 2 },
new() { Value = 5 },
new() { Value = 4 }
];
Series = [
new LineSeries<ObservableValue>(ObservableValues)
];
}
[RelayCommand]
public void AddItem()
{
var randomValue = _random.Next(1, 10);
// the new value is added to the collection // mark
// the chart is listening, and will update and animate the change // mark
ObservableValues.Add(new() { Value = randomValue });
}
[RelayCommand]
public void RemoveItem()
{
if (ObservableValues.Count == 0) return;
// the last value is removed from the collection // mark
// the chart is listening, and will update and animate the change // mark
ObservableValues.RemoveAt(0);
}
[RelayCommand]
public void UpdateItem()
{
var randomValue = _random.Next(1, 10);
var lastItem = ObservableValues[ObservableValues.Count - 1];
// becase lastItem is an ObservableObject and implements INotifyPropertyChanged // mark
// the chart is listening for changes in the Value property // mark
// and will update and animate the change // mark
lastItem.Value = randomValue;
}
[RelayCommand]
public void ReplaceItem()
{
var randomValue = _random.Next(1, 10);
var randomIndex = _random.Next(0, ObservableValues.Count - 1);
// replacing and item also triggers the chart to update and animate the change // mark
ObservableValues[randomIndex] = new(randomValue);
}
[RelayCommand]
public void AddSeries()
{
var values = Enumerable.Range(0, 3)
.Select(_ => _random.Next(0, 10))
.ToArray();
// a new line series is added to the chart // mark
Series.Add(new LineSeries<int>(values));
}
[RelayCommand]
public void RemoveSeries()
{
if (Series.Count == 1) return;
// the last series is removed from the chart // mark
Series.RemoveAt(Series.Count - 1);
}
}
// All LiveCharts objects (Series, Axes, etc) implement INotifyPropertyChanged // mark
// this means that the chart is listening for changes in the properties // mark
// the chart will reflect the changes and animate them // mark
Form code behind
using System.Threading.Tasks;
using System.Windows.Forms;
using LiveChartsCore.SkiaSharpView.WinForms;
using ViewModelsSamples.Lines.AutoUpdate;
namespace WinFormsSample.Lines.AutoUpdate;
public partial class View : UserControl
{
private readonly CartesianChart _cartesianChart;
private readonly ViewModel _viewModel;
private bool? _isStreaming = false;
public View()
{
InitializeComponent();
Size = new System.Drawing.Size(100, 100);
_viewModel = new ViewModel();
_cartesianChart = new CartesianChart
{
Series = _viewModel.Series,
// out of livecharts properties...
Location = new System.Drawing.Point(0, 50),
Size = new System.Drawing.Size(100, 50),
Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom
};
Controls.Add(_cartesianChart);
var b1 = new Button { Text = "Add item", Location = new System.Drawing.Point(0, 0) };
b1.Click += (object sender, System.EventArgs e) => _viewModel.AddItem();
Controls.Add(b1);
var b2 = new Button { Text = "Replace item", Location = new System.Drawing.Point(80, 0) };
b2.Click += (object sender, System.EventArgs e) => _viewModel.ReplaceItem();
Controls.Add(b2);
var b3 = new Button { Text = "Remove item", Location = new System.Drawing.Point(160, 0) };
b3.Click += (object sender, System.EventArgs e) => _viewModel.RemoveItem();
Controls.Add(b3);
var b4 = new Button { Text = "Add series", Location = new System.Drawing.Point(240, 0) };
b4.Click += (object sender, System.EventArgs e) => _viewModel.AddSeries();
Controls.Add(b4);
var b5 = new Button { Text = "Remove series", Location = new System.Drawing.Point(320, 0) };
b5.Click += (object sender, System.EventArgs e) => _viewModel.RemoveSeries();
Controls.Add(b5);
var b6 = new Button { Text = "Constant changes", Location = new System.Drawing.Point(400, 0) };
b6.Click += OnConstantChangesClick;
Controls.Add(b6);
}
private async void OnConstantChangesClick(object sender, System.EventArgs e)
{
_isStreaming = _isStreaming is null ? true : !_isStreaming;
while (_isStreaming.Value)
{
_viewModel.RemoveItem();
_viewModel.AddItem();
await Task.Delay(1000);
}
}
private void B1_Click(object sender, System.EventArgs e)
{
throw new System.NotImplementedException();
}
}