LiveCharts 在更改轴(MinValue 和 MaxValue)或添加新数据时重新呈现整个图

LiveCharts re-renders the entire plot when changing axis (MinValue and MaxValue) or adding new data

我创建了一个包含 5 个图表的折线图。每个有 250 点:每 1 分钟 1 点。我有一个移动 MinValueX 和 MaxValueX 的按钮。以及将新数据添加到 1 个图表的事件 UserControl_MouseDown。但是当我调用它时,它需要 15-20 秒才能将数据移动或添加到绘图中。我认为1250点不是很多。看起来它重新绘制了整个图形,而不是移动它或添加新数据。

我能否以某种方式将渲染行为更改为更优化?

这是我的折线图控件:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using LiveCharts;
using LiveCharts.Defaults;
using LiveCharts.Wpf;

namespace Chart
{
    /// <summary>
    /// Interaction logic for LineChart2.xaml
    /// </summary>
    public partial class LineChart2 : UserControl, INotifyPropertyChanged
    {
        #region properties
        public SeriesCollection SeriesCollection { get; set; }
        private Dictionary<string, List<DateTimePoint>> SeriesFullCollection { get; set; }
        public Func<double, string> XFormatter { get; set; }
        public long AxisStep { get; set; }
        public double MinValueX { get; set; }
        public double MaxValueX { get; set; }

        private DateTime minValueXDate;
        public DateTime MinValueXDate
        {
            get { return minValueXDate; }
            set { minValueXDate = value;
                MinValueX = value.Ticks;
                OnPropertyChanged("MinValueX");
            }
        }
        private DateTime maxValueXDate;
        public DateTime MaxValueXDate
        {
            get { return maxValueXDate; }
            set
            {
                maxValueXDate = value;
                MaxValueX = value.Ticks;
                OnPropertyChanged("MaxValueX");
            }
        }
        public double MinValueY { get; set; }
        public double MaxValueY { get; set; }
        public int ChartButtonsId { get; set; }
        #endregion
        public LineChart2()
        {
            SeriesFullCollection = new Dictionary<string, List<DateTimePoint>>();
            SeriesCollection = new SeriesCollection();
            this.Loaded += ControlLoaded;                     
            DataContext = this;            
            InitializeComponent();       
        }

        private void ControlLoaded(object sender, RoutedEventArgs e)
        {
            MinValueXDate = DateTime.Now.AddHours(-3.5);
            MaxValueXDate = DateTime.Now.AddHours(0.5);
            AxisStep = TimeSpan.FromMinutes(15).Ticks;
            XFormatter = val => new DateTime((long)val).ToString("HH:mm");

            MinValueY = 0;            //Test
            MaxValueY = 20;            //Test
            //Test
            Text2Add("A");
            Text2Add("B");
            Text2Add("C");
            Text2Add("D");
            Text2Add("E");
            RefreshCollection();
        }

        #region Add/Update/Remove
        public void AddChart(string title, Dictionary<DateTime, double> data)
        {
            List<DateTimePoint> dateTimePoints = new List<DateTimePoint>();
            foreach (var item in data)
                dateTimePoints.Add(new DateTimePoint(item.Key, item.Value));

            SeriesFullCollection.Add(title, dateTimePoints);
            AddToCollection(title);
        }
        public void UpdateChart(string title, Dictionary<DateTime, double> data)
        {
            var series = SeriesCollection.FirstOrDefault(x => x.Title == title);
            var seriesfull = SeriesFullCollection.FirstOrDefault(x => x.Key == title);
            if (series != null)
                foreach (var item in data)
                {
                    series.Values.Add(new DateTimePoint(item.Key, item.Value));
                    seriesfull.Value.Add(new DateTimePoint(item.Key, item.Value));
                }
        }
        public void RemoveChart(string title)
        {
            var series = SeriesCollection.FirstOrDefault(x => x.Title == title);
            var seriesfull = SeriesFullCollection.FirstOrDefault(x => x.Key == title);
            if (series != null)
            {
                SeriesCollection.Remove(series);
                SeriesFullCollection.Remove(seriesfull.Key);
            }
            RefreshCollection();
        }

        private void AddToCollection(string title)
        {
            var seriesfull = SeriesFullCollection.FirstOrDefault(x => x.Key == title);
            var l = new LineSeries();
            l.Title = seriesfull.Key;
            l.Values = new ChartValues<DateTimePoint>();
            l.PointGeometrySize = 2;
            l.Values.AddRange(seriesfull.Value.Where(x => x.DateTime >= MinValueXDate && x.DateTime <= MaxValueXDate));
            SeriesCollection.Add(l);
        }
        #endregion
        #region EventsMethod
        public void MoveNext()
        {
            MinValueXDate = MinValueXDate.AddTicks(AxisStep * 2);
            MaxValueXDate = MaxValueXDate.AddTicks(AxisStep * 2);
            //RefreshCollection();
        }
        public void MovePrevious()
        {
            MinValueXDate = MinValueXDate.AddTicks(-AxisStep * 2);
            MaxValueXDate = MaxValueXDate.AddTicks(-AxisStep * 2);
            //RefreshCollection();
        }
        public void ZoomIn()
        {
            MinValueXDate = MinValueXDate.AddTicks(AxisStep);
            MaxValueXDate = MaxValueXDate.AddTicks(-AxisStep);
            //RefreshCollection();
        }
        public void ZoomOut()
        {
            MinValueXDate = MinValueXDate.AddTicks(-AxisStep);
            MaxValueXDate = MaxValueXDate.AddTicks(AxisStep);
            //RefreshCollection();
        }
        public void ChangeDate()
        {

        }
        #endregion
        private void RefreshCollection()
        {
            SeriesCollection.Clear();
            foreach (var item in SeriesFullCollection)
            {
                var l = new LineSeries();
                l.Title = item.Key;
                l.Values = new ChartValues<DateTimePoint>();
                l.PointGeometrySize = 2;
                l.Values.AddRange(item.Value.Where(x => x.DateTime >= MinValueXDate && x.DateTime <= MaxValueXDate));
                SeriesCollection.Add(l);
            }
        }
        #region Test
        private void Text2Add(string name)
        {
            var d = new Dictionary<DateTime, double>();
            int last = 0;
            Random r = new Random();
            for (int i = 0; i < 250; i++)
            {
                var next = r.Next(last == 0 ? 0 : last - 1, last == 20 ? 20 : last + 2);
                last = next;
                d.Add(DateTime.Now.AddMinutes(-250+ i), next);
            }
            AddChart(name, d);
        }
        private int aaaa = 0;

        public event PropertyChangedEventHandler PropertyChanged;

        private void UserControl_MouseDown(object sender, MouseButtonEventArgs e)
        {
            var d = new Dictionary<DateTime, double>();
            int last = 0;
            Random r = new Random();
            for (int i = 0; i < 10; i++)
            {
                var next = r.Next(last == 0 ? 0 : last - 1, last == 20 ? 20 : last + 2);
                last = next;
                d.Add(DateTime.Now.AddMinutes(aaaa + i), next);
            }
            aaaa += 10;
            UpdateChart("A", d);
        }
        #endregion
        protected void OnPropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            MinValueXDate = MinValueXDate.AddTicks(AxisStep * 2);
            MaxValueXDate = MaxValueXDate.AddTicks(AxisStep * 2);
        }
    }
}

和Xaml:

<UserControl x:Class="Chart.LineChart2"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
         xmlns:local="clr-namespace:Chart"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="800" MouseDown="UserControl_MouseDown">
    <Grid Background="White">
        <lvc:CartesianChart Series="{Binding SeriesCollection}" LegendLocation="Right" >
            <lvc:CartesianChart.AxisY>
                <lvc:Axis Title="Value" MinValue="{Binding MinValueY}" MaxValue="{Binding MaxValueY}"></lvc:Axis>
            </lvc:CartesianChart.AxisY>
            <lvc:CartesianChart.AxisX>
                <lvc:Axis LabelFormatter="{Binding XFormatter}" MinValue="{Binding MinValueX}" MaxValue="{Binding MaxValueX}">
                    <lvc:Axis.Separator>
                        <lvc:Separator Step="{Binding AxisStep}" />
                    </lvc:Axis.Separator>
                </lvc:Axis>
            </lvc:CartesianChart.AxisX>
        </lvc:CartesianChart>
        <Button Height="20" Width="50" Click="Button_Click" Margin="740,10,10,270"/>
    </Grid>
</UserControl>

有一个 link 要分页 peformance tips

获得更好性能的建议可能性是:

  • 禁用动画
  • 减少图表中的形状数量
  • 尽可能冻结
  • 避免多次调用 .Add()

所以对于你的情况,我至少会尝试第一个和最后一个建议。