Hi,
I have been working with an sfChart and I am trying to give it functionality similar to other stock chart platforms.
However, the performance seems horrendous, and I'm concerned that there is a memory leak somewhere. I'm not sure if my implementation is the cause or if this control is really not as performant as expected.
I added my implementation at the end of this post. In the code I am adding a button and chart to the main window. On clicking the button, I clear the binded observable collection and add 11500 candles to it.
I really hope to get this chart to be much more performant than what I am currently experiencing and would appreciate any help.
The issues that I see listed out are:
1 - the chart takes multiple seconds to render the candles.
2 - The window and control become very slow and delayed when I try to:
a) scroll along the chart
b) change the zoom factor with the scroll bar
c) resize the window.
3 - when loading these 11500 candles into the chart. it takes up almost 600 mb of memory. that seems like a lot, since on other stock platforms I have no problems loading up 5-6 charts with thousands of candles on them. so is that much memory usage correct?
4 - a possibly memory leak somewhere..... In my code I make sure to clear the observable collection that is binded to the chart before reloading it. However, when the chart starts to re-render the candles, I continue to see memory continue to build up every time that I try to repopulate. I would think that it should stay the same after the initial render. I have attached pictures in memleak.zip
Implementation
<Window x:Class="WPFSfChartTesting.MainWindow"
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:chart="clr-namespace:Syncfusion.UI.Xaml.Charts;assembly=Syncfusion.SfChart.WPF"
xmlns:local="clr-namespace:WPFSfChartTesting"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button x:Name="populateBtn" Content="Populate" Click="populateBtn_Click"/>
<chart:SfChart x:Name="chart"
Grid.Row ="1">
<chart:SfChart.PrimaryAxis>
<chart:CategoryAxis x:Name="xAxis"
EnableScrollBar="True"
Interval="1"
LabelFormat="ddd d MMM HH:mm"/>
</chart:SfChart.PrimaryAxis>
<chart:CandleSeries
x:Name="candleSeries"
ItemsSource="{Binding RenderedBars}"
XBindingPath="Date"
High="High"
Low="Low"
Open="Open"
Close="Close"
BearFillColor="Maroon"
BullFillColor="MidnightBlue"/>
</chart:SfChart>
</Grid>
</Window>
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
namespace WPFSfChartTesting
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
ViewModel _vm;
public MainWindow()
{
InitializeComponent();
_vm = new();
DataContext = _vm;
}
private void populateBtn_Click(object sender, RoutedEventArgs e)
{
_vm.Populate();
int barsToSee = 500;
double zoomFactor = 0;
double zoomPosition = 0;
double pctBars = 1.0 * barsToSee / _vm.RenderedBars.Count;
zoomFactor = pctBars;
zoomPosition = 1 - pctBars;
xAxis.ZoomFactor = zoomFactor;
xAxis.ZoomPosition = zoomPosition;
}
}
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
public ObservableCollection<BarModel> RenderedBars { get; set; } = new();
public void Populate()
{
RenderedBars.Clear();
Random random = new();
double min = 0;
double max = 1;
DateTime date = new DateTime(2021, 1, 1);
for (int i = 0; i < 11500; i++)
{
double o = random.NextDouble();
double c = random.NextDouble();
double h = Math.Max(o, c) + Math.Abs(o - c);
double l = Math.Min(o, c) - Math.Abs(o - c);
RenderedBars.Add(new BarModel(date, o, h, l, c));
date = date.AddMinutes(5);
}
}
}
public class BarModel
{
public DateTime Date { get; private set; }
public double Open { get; private set; }
public double High { get; private set; }
public double Low { get; private set; }
public double Close { get; private set; }
public BarModel(DateTime date, double open, double high, double low, double close)
{
Date = date;
Open = open;
High = high;
Low = low;
Close = close;
}
}
}
That works so much better, thank you.
Hi Lorenzo,
Thanks for your update.
Please let us know if you have any further assistance.
Regards,
Yuvaraj.