ZXW
ZXW

Reputation: 1

How to improve WPF liveCharts render performance?

This is my first time to post a question here. So, please forgive my poor written English. I try my best to make it more clear. I wrote a WPF program, which uses LiveCharts control to display data. The XAML and the code-behind are listed below, and I think it is very simple. The problem is, CPU usage percent is too high. After running about 30 minutes, about half of the cpu are consumed. Is it normal? Is there anyone who can give me some advice to lower the CPU usage percentage and improve the program performance?

// this is the xaml
<Window x:Class="lvChartTest.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:local="clr-namespace:lvChartTest"
        xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="300" d:DataContext="{d:DesignInstance local:MainWindow}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <lvc:CartesianChart Series="{Binding ASeriesCollection}" 
                            Hoverable="False" LegendLocation="Left">
            <lvc:CartesianChart.AxisX>
                <lvc:Axis Title="Salesman" Labels="{Binding ALabels}"></lvc:Axis>
            </lvc:CartesianChart.AxisX>
            <lvc:CartesianChart.AxisY>
                <lvc:Axis Title="Sold Apps" LabelFormatter="{Binding AFormatter}"></lvc:Axis>
            </lvc:CartesianChart.AxisY>
        </lvc:CartesianChart>

        <lvc:CartesianChart Grid.Row="1" Series="{Binding BSeriesCollection}" 
                            Hoverable="False"  LegendLocation="Right" >
            <lvc:CartesianChart.AxisX>
                <lvc:Axis Title="Month" Labels="{Binding BLabels}"></lvc:Axis>
            </lvc:CartesianChart.AxisX>
            <lvc:CartesianChart.AxisY>
                <lvc:Axis Title="Sales" LabelFormatter="{Binding BFormatter}"></lvc:Axis>
            </lvc:CartesianChart.AxisY>
        </lvc:CartesianChart>
    </Grid>
</Window>

// this is the code behind
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;

        ASeriesCollection = new SeriesCollection
        {
            new ColumnSeries
            {
                Title = "2015",
                PointGeometry=null,

                Values = new ChartValues<ObservableValue>
                {
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0),
                    new ObservableValue(0)
                }
            }
        };

        ALabels = new[] { "Maria", "Susan", "Charles", "Frida" };
        AFormatter = value => value.ToString("N");

        BSeriesCollection = new SeriesCollection
        {
            new LineSeries
            {
                Title = "Series 1",
                PointGeometry=null,
                Values = new ChartValues<ObservableValue>
                {
                    new ObservableValue(4),
                    new ObservableValue(2),
                    new ObservableValue(8),
                    new ObservableValue(2),
                    new ObservableValue(3),
                    new ObservableValue(0),
                    new ObservableValue(1),
                }  
            }
        };

        BLabels = new[] { "Jan", "Feb", "Mar", "Apr", "May" };
        BFormatter = value => value.ToString("C");

        DispatcherTimer timerForDisplayData = new DispatcherTimer();
        timerForDisplayData.Interval = TimeSpan.FromSeconds(1);
        timerForDisplayData.Tick += OnDisplayData;
        timerForDisplayData.Start();
    }

    private void OnDisplayData(object sender, EventArgs e)
    {
        var r = new Random();

        foreach (var series in ASeriesCollection)
        {
            foreach (var observable in series.Values.Cast<ObservableValue>())
            {
                observable.Value = r.Next(0, 10);
            }
        }

        foreach (var series in BSeriesCollection)
        {
            if (series.Values.Count >= 500)
            {
                series.Values.RemoveAt(0);
            }

            series.Values.Add(new ObservableValue(r.Next(0, 100)));
        }
    }

    public SeriesCollection ASeriesCollection { get; set; }
    public string[] ALabels { get; set; }
    public Func<double, string> AFormatter { get; set; }

    public SeriesCollection BSeriesCollection { get; set; }
    public string[] BLabels { get; set; }
    public Func<double, string> BFormatter { get; set; }

}

Upvotes: 0

Views: 1742

Answers (3)

Steve
Steve

Reputation: 252

With the free charts, the only thing that helped was to set PointGeometry to null. Even disabling animations, tooltip and hover didn't help. With Geared, performance is amazing, even with PointGeometry, tooltip and hover enabled.

Upvotes: 0

Carlos Bomtempo
Carlos Bomtempo

Reputation: 138

Try to move your OnDisplayData code to be inside a using statement that disables the dispatcher like that:

using(var dispatcher = Dispatcher.DisableProcessing())
{
    /* do work while the dispatcher processing is disabled... */
}

https://learn.microsoft.com/en-us/dotnet/api/system.windows.threading.dispatcher.disableprocessing?view=netframework-4.8

Upvotes: 0

SamTh3D3v
SamTh3D3v

Reputation: 9944

Unfortunately, there isn't much you can do (rather than losing features), the documentation suggests:

  • Losing the animation: DisableAnimations="True"
  • Losing the tooltip DataTooltip="{x:Null}"
  • Adding by rage rather than a simple add (replace your series.Values.Add with a series.Values.AddRange which basically means reducing the frequency)

Check out this page for more tips. On a side note as well, the LiveChars free version seems to be intentionally limited, and more people are struggling with the performances.

Upvotes: 1

Related Questions